Skip to content

Commit abe0aff

Browse files
committed
Added BNLike input type for chain IDs in toChecksumAddress() and isValidChecksumAddress(), expanded tests
1 parent 24279bf commit abe0aff

File tree

2 files changed

+45
-4
lines changed

2 files changed

+45
-4
lines changed

src/account.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import assert from 'assert'
22
import BN from 'bn.js'
33
import * as rlp from 'rlp'
4-
import { stripHexPrefix } from 'ethjs-util'
4+
import { isHexString, stripHexPrefix } from 'ethjs-util'
55
import { KECCAK256_RLP, KECCAK256_NULL } from './constants'
66
import { zeros, bufferToHex, toBuffer } from './bytes'
77
import { keccak, keccak256, keccakFromString, rlphash } from './hash'
@@ -137,11 +137,23 @@ export const isValidAddress = function(hexAddress: string): boolean {
137137
* WARNING: Checksums with and without the chainId will differ. As of 2019-06-26, the most commonly
138138
* used variation in Ethereum was without the chainId. This may change in the future.
139139
*/
140-
export const toChecksumAddress = function(hexAddress: string, eip1191ChainId?: number): string {
140+
export const toChecksumAddress = function(hexAddress: string, eip1191ChainId?: BNLike): string {
141141
assertIsHexString(hexAddress)
142+
if (typeof eip1191ChainId === 'string' && !isHexString(eip1191ChainId)) {
143+
throw new Error(`A chainId string must be provided with a 0x-prefix, given: ${eip1191ChainId}`)
144+
}
142145
const address = stripHexPrefix(hexAddress).toLowerCase()
143146

144-
const prefix = eip1191ChainId !== undefined ? eip1191ChainId.toString() + '0x' : ''
147+
let prefix = ''
148+
if (eip1191ChainId) {
149+
// Performance optimization
150+
if (typeof eip1191ChainId === 'number' && Number.isSafeInteger(eip1191ChainId)) {
151+
prefix = eip1191ChainId.toString()
152+
} else {
153+
prefix = new BN(toBuffer(eip1191ChainId)).toString()
154+
}
155+
prefix += '0x'
156+
}
145157

146158
const hash = keccakFromString(prefix + address).toString('hex')
147159
let ret = '0x'
@@ -164,7 +176,7 @@ export const toChecksumAddress = function(hexAddress: string, eip1191ChainId?: n
164176
*/
165177
export const isValidChecksumAddress = function(
166178
hexAddress: string,
167-
eip1191ChainId?: number
179+
eip1191ChainId?: BNLike
168180
): boolean {
169181
return isValidAddress(hexAddress) && toChecksumAddress(hexAddress, eip1191ChainId) === hexAddress
170182
}

test/account.spec.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,9 +602,27 @@ describe('.toChecksumAddress()', function() {
602602
for (const [chainId, addresses] of Object.entries(eip1191ChecksummAddresses)) {
603603
for (const addr of addresses) {
604604
assert.equal(toChecksumAddress(addr.toLowerCase(), Number(chainId)), addr)
605+
assert.equal(toChecksumAddress(addr.toLowerCase(), Buffer.from([chainId])), addr)
606+
assert.equal(toChecksumAddress(addr.toLowerCase(), new BN(chainId)), addr)
607+
assert.equal(
608+
toChecksumAddress(addr.toLowerCase(), '0x' + Buffer.from([chainId]).toString('hex')),
609+
addr
610+
)
605611
}
606612
}
607613
})
614+
it('Should encode large chain ids greater than MAX_INTEGER correctly', function() {
615+
const addr = '0x88021160C5C792225E4E5452585947470010289D'
616+
const chainIDBuffer = Buffer.from('796f6c6f763378', 'hex')
617+
assert.equal(toChecksumAddress(addr.toLowerCase(), chainIDBuffer), addr)
618+
assert.equal(toChecksumAddress(addr.toLowerCase(), new BN(chainIDBuffer)), addr)
619+
assert.equal(
620+
toChecksumAddress(addr.toLowerCase(), '0x' + chainIDBuffer.toString('hex')),
621+
addr
622+
)
623+
const chainIDNumber = parseInt(chainIDBuffer.toString('hex'), 16)
624+
assert.equal(toChecksumAddress(addr.toLowerCase(), chainIDNumber), addr)
625+
})
608626
})
609627

610628
describe('input format', function() {
@@ -613,6 +631,11 @@ describe('.toChecksumAddress()', function() {
613631
toChecksumAddress('52908400098527886E0F7030069857D2E4169EE7'.toLowerCase())
614632
})
615633
})
634+
it('Should throw when the chainId is not hex-prefixed', function() {
635+
assert.throws(function() {
636+
toChecksumAddress('0xde709f2102306220921060314715629080e2fb77', '1234')
637+
})
638+
})
616639
})
617640
})
618641

@@ -633,6 +656,12 @@ describe('.isValidChecksumAddress()', function() {
633656
for (const [chainId, addresses] of Object.entries(eip1191ChecksummAddresses)) {
634657
for (const addr of addresses) {
635658
assert.equal(isValidChecksumAddress(addr, Number(chainId)), true)
659+
assert.equal(isValidChecksumAddress(addr, Buffer.from([chainId])), true)
660+
assert.equal(isValidChecksumAddress(addr, new BN(chainId)), true)
661+
assert.equal(
662+
isValidChecksumAddress(addr, '0x' + Buffer.from([chainId]).toString('hex')),
663+
true
664+
)
636665
}
637666
}
638667
})

0 commit comments

Comments
 (0)