diff --git a/src/utils/eth.ts b/src/utils/eth.ts index 6534ce99..5bf526e2 100644 --- a/src/utils/eth.ts +++ b/src/utils/eth.ts @@ -12,6 +12,23 @@ export type HexEthAddress = HexString<40> const ETH_ADDR_BYTES_LENGTH = 20 const ETH_ADDR_HEX_LENGTH = 40 +export function capitalizeAddressERC55(address: string): string { + if (address.startsWith('0x')) { + address = address.slice(2) + } + const addressHash = keccak256(address.toLowerCase()) + let result = '0x' + for (let i = 0; i < address.length; i++) { + if (parseInt(addressHash[i], 16) > 7) { + result += address[i].toUpperCase() + } else { + result += address[i].toLowerCase() + } + } + + return result +} + export function makeEthAddress(address: EthAddress | Uint8Array | string | unknown): EthAddress { if (typeof address === 'string') { const hexAddr = makeHexString(address, ETH_ADDR_HEX_LENGTH) diff --git a/src/utils/expose.ts b/src/utils/expose.ts index fb34551f..02b56c17 100644 --- a/src/utils/expose.ts +++ b/src/utils/expose.ts @@ -27,6 +27,7 @@ export { export { EthAddress, + capitalizeAddressERC55, ethToSwarmAddress, fromLittleEndian, isHexEthAddress, diff --git a/test/unit/utils/eth.spec.ts b/test/unit/utils/eth.spec.ts index be135e51..2d52e93d 100644 --- a/test/unit/utils/eth.spec.ts +++ b/test/unit/utils/eth.spec.ts @@ -1,18 +1,51 @@ /* eslint @typescript-eslint/no-empty-function: 0 */ +import { expect } from 'chai' +import sinon from 'sinon' +import { wrapBytesWithHelpers } from '../../../src/utils/bytes' import { - makeEthereumWalletSigner, + capitalizeAddressERC55, ethToSwarmAddress, fromLittleEndian, isHexEthAddress, JsonRPC, + makeEthereumWalletSigner, toLittleEndian, } from '../../../src/utils/eth' import { HexString, hexToBytes } from '../../../src/utils/hex' -import { wrapBytesWithHelpers } from '../../../src/utils/bytes' -import { expect } from 'chai' -import sinon from 'sinon' describe('eth', () => { + describe('capitalizeAddressERC55', () => { + it('should calculate checksum for address', () => { + // All caps + expect(capitalizeAddressERC55('0x52908400098527886E0F7030069857D2E4169EE7')).to.be( + '0x52908400098527886E0F7030069857D2E4169EE7', + ) + expect(capitalizeAddressERC55('0x8617E340B3D01FA5F11F306F4090FD50E238070D')).to.be( + '0x8617E340B3D01FA5F11F306F4090FD50E238070D', + ) + // All Lower + expect(capitalizeAddressERC55('0xde709f2102306220921060314715629080e2fb77')).to.be( + '0xde709f2102306220921060314715629080e2fb77', + ) + expect(capitalizeAddressERC55('0x27b1fdb04752bbc536007a920d24acb045561c26')).to.be( + '0x27b1fdb04752bbc536007a920d24acb045561c26', + ) + // Normal + expect(capitalizeAddressERC55('0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed')).to.be( + '0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed', + ) + expect(capitalizeAddressERC55('0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359')).to.be( + '0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359', + ) + expect(capitalizeAddressERC55('0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB')).to.be( + '0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB', + ) + expect(capitalizeAddressERC55('0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb')).to.be( + '0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb', + ) + }) + }) + describe('isEthAddress', () => { const testValues = [ { value: () => {}, result: false },