Skip to content
This repository was archived by the owner on Jun 17, 2021. It is now read-only.

Commit 3b10850

Browse files
authored
Merge pull request #204 from ethereumjs/eip1191
Implement EIP1191
2 parents a7bfe26 + beecf2d commit 3b10850

File tree

3 files changed

+135
-35
lines changed

3 files changed

+135
-35
lines changed

docs/README.md

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ ___
165165

166166
**● publicToAddress**: *[pubToAddress]()* = pubToAddress
167167

168-
*Defined in [account.ts:151](https://github.com/ethereumjs/ethereumjs-util/blob/master/src/account.ts#L151)*
168+
*Defined in [account.ts:163](https://github.com/ethereumjs/ethereumjs-util/blob/master/src/account.ts#L163)*
169169

170170
___
171171
<a id="setlength"></a>
@@ -225,7 +225,7 @@ Converts a `Buffer` or `Array` to JSON.
225225
| ba | `any` | (Buffer\|Array) |
226226

227227
**Returns:** `any`
228-
(Array|String|null)
228+
(Array\|String\|null)
229229

230230
___
231231
<a id="buffertohex"></a>
@@ -236,7 +236,7 @@ ___
236236

237237
*Defined in [bytes.ts:111](https://github.com/ethereumjs/ethereumjs-util/blob/master/src/bytes.ts#L111)*
238238

239-
Converts a `Buffer` into a hex `String`.
239+
Converts a `Buffer` into a `0x`\-prefixed hex `String`.
240240

241241
**Parameters:**
242242

@@ -376,7 +376,7 @@ ___
376376

377377
**generateAddress**(from: *`Buffer`*, nonce: *`Buffer`*): `Buffer`
378378

379-
*Defined in [account.ts:63](https://github.com/ethereumjs/ethereumjs-util/blob/master/src/account.ts#L63)*
379+
*Defined in [account.ts:75](https://github.com/ethereumjs/ethereumjs-util/blob/master/src/account.ts#L75)*
380380

381381
Generates an address of a newly created contract.
382382

@@ -396,7 +396,7 @@ ___
396396

397397
**generateAddress2**(from: *`Buffer` \| `string`*, salt: *`Buffer` \| `string`*, initCode: *`Buffer` \| `string`*): `Buffer`
398398

399-
*Defined in [account.ts:83](https://github.com/ethereumjs/ethereumjs-util/blob/master/src/account.ts#L83)*
399+
*Defined in [account.ts:95](https://github.com/ethereumjs/ethereumjs-util/blob/master/src/account.ts#L95)*
400400

401401
Generates an address for a contract created using CREATE2.
402402

@@ -436,7 +436,7 @@ ___
436436

437437
**importPublic**(publicKey: *`Buffer`*): `Buffer`
438438

439-
*Defined in [account.ts:174](https://github.com/ethereumjs/ethereumjs-util/blob/master/src/account.ts#L174)*
439+
*Defined in [account.ts:186](https://github.com/ethereumjs/ethereumjs-util/blob/master/src/account.ts#L186)*
440440

441441
Converts a public key to the Ethereum format.
442442

@@ -455,7 +455,7 @@ ___
455455

456456
**isPrecompiled**(address: *`Buffer` \| `string`*): `boolean`
457457

458-
*Defined in [account.ts:105](https://github.com/ethereumjs/ethereumjs-util/blob/master/src/account.ts#L105)*
458+
*Defined in [account.ts:117](https://github.com/ethereumjs/ethereumjs-util/blob/master/src/account.ts#L117)*
459459

460460
Returns true if the supplied address belongs to a precompiled account (Byzantium).
461461

@@ -491,17 +491,20 @@ ___
491491

492492
### `<Const>` isValidChecksumAddress
493493

494-
**isValidChecksumAddress**(address: *`string`*): `boolean`
494+
**isValidChecksumAddress**(address: *`string`*, eip1191ChainId?: *`undefined` \| `number`*): `boolean`
495495

496-
*Defined in [account.ts:54](https://github.com/ethereumjs/ethereumjs-util/blob/master/src/account.ts#L54)*
496+
*Defined in [account.ts:66](https://github.com/ethereumjs/ethereumjs-util/blob/master/src/account.ts#L66)*
497497

498498
Checks if the address is a valid checksummed address.
499499

500+
See toChecksumAddress' documentation for details about the eip1191ChainId parameter.
501+
500502
**Parameters:**
501503

502504
| Name | Type |
503505
| ------ | ------ |
504506
| address | `string` |
507+
| `Optional` eip1191ChainId | `undefined` \| `number` |
505508

506509
**Returns:** `boolean`
507510

@@ -512,7 +515,7 @@ ___
512515

513516
**isValidPrivate**(privateKey: *`Buffer`*): `boolean`
514517

515-
*Defined in [account.ts:113](https://github.com/ethereumjs/ethereumjs-util/blob/master/src/account.ts#L113)*
518+
*Defined in [account.ts:125](https://github.com/ethereumjs/ethereumjs-util/blob/master/src/account.ts#L125)*
516519

517520
Checks if the private key satisfies the rules of the curve secp256k1.
518521

@@ -531,7 +534,7 @@ ___
531534

532535
**isValidPublic**(publicKey: *`Buffer`*, sanitize?: *`boolean`*): `boolean`
533536

534-
*Defined in [account.ts:123](https://github.com/ethereumjs/ethereumjs-util/blob/master/src/account.ts#L123)*
537+
*Defined in [account.ts:135](https://github.com/ethereumjs/ethereumjs-util/blob/master/src/account.ts#L135)*
535538

536539
Checks if the public key satisfies the rules of the curve secp256k1 and the requirements of Ethereum.
537540

@@ -632,7 +635,7 @@ ___
632635

633636
**privateToAddress**(privateKey: *`Buffer`*): `Buffer`
634637

635-
*Defined in [account.ts:157](https://github.com/ethereumjs/ethereumjs-util/blob/master/src/account.ts#L157)*
638+
*Defined in [account.ts:169](https://github.com/ethereumjs/ethereumjs-util/blob/master/src/account.ts#L169)*
636639

637640
Returns the ethereum address of a given private key.
638641

@@ -651,7 +654,7 @@ ___
651654

652655
**privateToPublic**(privateKey: *`Buffer`*): `Buffer`
653656

654-
*Defined in [account.ts:165](https://github.com/ethereumjs/ethereumjs-util/blob/master/src/account.ts#L165)*
657+
*Defined in [account.ts:177](https://github.com/ethereumjs/ethereumjs-util/blob/master/src/account.ts#L177)*
655658

656659
Returns the ethereum public key of a given private key.
657660

@@ -670,7 +673,7 @@ ___
670673

671674
**pubToAddress**(pubKey: *`Buffer`*, sanitize?: *`boolean`*): `Buffer`
672675

673-
*Defined in [account.ts:142](https://github.com/ethereumjs/ethereumjs-util/blob/master/src/account.ts#L142)*
676+
*Defined in [account.ts:154](https://github.com/ethereumjs/ethereumjs-util/blob/master/src/account.ts#L154)*
674677

675678
Returns the ethereum address of a given public key. Accepts "Ethereum public keys" and SEC1 encoded keys.
676679

@@ -742,7 +745,7 @@ Left Pads an `Array` or `Buffer` with leading zeros till it has `length` bytes.
742745
| `Default value` right | `boolean` | false | whether to start padding form the left or right |
743746

744747
**Returns:** `any`
745-
(Buffer|Array)
748+
(Buffer\|Array)
746749

747750
___
748751
<a id="setlengthright"></a>
@@ -763,7 +766,7 @@ Right Pads an `Array` or `Buffer` with leading zeros till it has `length` bytes.
763766
| length | `number` | the number of bytes the output should be |
764767

765768
**Returns:** `any`
766-
(Buffer|Array)
769+
(Buffer\|Array)
767770

768771
___
769772
<a id="sha256"></a>
@@ -808,17 +811,22 @@ ___
808811

809812
### `<Const>` toChecksumAddress
810813

811-
**toChecksumAddress**(address: *`string`*): `string`
814+
**toChecksumAddress**(address: *`string`*, eip1191ChainId?: *`undefined` \| `number`*): `string`
812815

813-
*Defined in [account.ts:35](https://github.com/ethereumjs/ethereumjs-util/blob/master/src/account.ts#L35)*
816+
*Defined in [account.ts:42](https://github.com/ethereumjs/ethereumjs-util/blob/master/src/account.ts#L42)*
814817

815818
Returns a checksummed address.
816819

820+
If a eip1191ChainId is provided, the chainId will be included in the checksum calculation. This has the effect of checksummed addresses for one chain having invalid checksums for others. For more details, consult EIP-1191.
821+
822+
WARNING: Checksums with and without the chainId will differ. As of 2019-06-26, the most commonly used variation in Ethereum was without the chainId. This may change in the future.
823+
817824
**Parameters:**
818825

819826
| Name | Type |
820827
| ------ | ------ |
821828
| address | `string` |
829+
| `Optional` eip1191ChainId | `undefined` \| `number` |
822830

823831
**Returns:** `string`
824832

@@ -882,7 +890,7 @@ Trims leading zeros from a `Buffer` or an `Array`.
882890
| a | `any` | (Buffer\|Array\|String) |
883891

884892
**Returns:** `any`
885-
(Buffer|Array|String)
893+
(Buffer\|Array\|String)
886894

887895
___
888896
<a id="zeroaddress"></a>

src/account.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,20 @@ export const isZeroAddress = function(address: string): boolean {
3131

3232
/**
3333
* Returns a checksummed address.
34+
*
35+
* If a eip1191ChainId is provided, the chainId will be included in the checksum calculation. This
36+
* has the effect of checksummed addresses for one chain having invalid checksums for others.
37+
* For more details, consult EIP-1191.
38+
*
39+
* WARNING: Checksums with and without the chainId will differ. As of 2019-06-26, the most commonly
40+
* used variation in Ethereum was without the chainId. This may change in the future.
3441
*/
35-
export const toChecksumAddress = function(address: string): string {
42+
export const toChecksumAddress = function(address: string, eip1191ChainId?: number): string {
3643
address = ethjsUtil.stripHexPrefix(address).toLowerCase()
37-
const hash = keccak(address).toString('hex')
44+
45+
const prefix = eip1191ChainId !== undefined ? eip1191ChainId.toString() + '0x' : ''
46+
47+
const hash = keccak(prefix + address).toString('hex')
3848
let ret = '0x'
3949

4050
for (let i = 0; i < address.length; i++) {
@@ -50,9 +60,11 @@ export const toChecksumAddress = function(address: string): string {
5060

5161
/**
5262
* Checks if the address is a valid checksummed address.
63+
*
64+
* See toChecksumAddress' documentation for details about the eip1191ChainId parameter.
5365
*/
54-
export const isValidChecksumAddress = function(address: string): boolean {
55-
return isValidAddress(address) && toChecksumAddress(address) === address
66+
export const isValidChecksumAddress = function(address: string, eip1191ChainId?: number): boolean {
67+
return isValidAddress(address) && toChecksumAddress(address, eip1191ChainId) === address
5668
}
5769

5870
/**

test/index.js

Lines changed: 92 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -642,7 +642,7 @@ describe('isValidSignature', function () {
642642
// FIXME: add homestead test
643643
})
644644

645-
const checksumAddresses = [
645+
const eip55ChecksumAddresses = [
646646
// All caps
647647
'0x52908400098527886E0F7030069857D2E4169EE7',
648648
'0x8617E340B3D01FA5F11F306F4090FD50E238070D',
@@ -656,23 +656,103 @@ const checksumAddresses = [
656656
'0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb'
657657
]
658658

659+
const eip1191ChecksummAddresses = {
660+
1: [
661+
'0x88021160c5C792225E4E5452585947470010289d',
662+
'0x27b1FdB04752bBc536007a920D24ACB045561c26',
663+
'0x52908400098527886e0f7030069857D2e4169EE7',
664+
'0x5aaeB6053f3E94C9b9A09f33669435e7Ef1bEAed',
665+
'0x8617E340b3d01FA5F11F306f4090FD50E238070d',
666+
'0xd1220a0CF47C7B9Be7A2E6ba89F429762E7B9Adb',
667+
'0xdBf03b407c01e7cD3CBea99509d93f8dDDC8C6fB',
668+
'0xDe709F2102306220921060314715629080E2fb77',
669+
'0xfb6916095Ca1dF60bB79cE92ce3ea74C37c5D359',
670+
],
671+
30: [
672+
'0x6549F4939460DE12611948B3F82B88C3C8975323',
673+
'0x27b1FdB04752BBc536007A920D24ACB045561c26',
674+
'0x3599689E6292B81B2D85451025146515070129Bb',
675+
'0x52908400098527886E0F7030069857D2E4169ee7',
676+
'0x5aaEB6053f3e94c9b9a09f33669435E7ef1bEAeD',
677+
'0x8617E340b3D01Fa5f11f306f4090fd50E238070D',
678+
'0xD1220A0Cf47c7B9BE7a2e6ba89F429762E7B9adB',
679+
'0xDBF03B407c01E7CD3cBea99509D93F8Dddc8C6FB',
680+
'0xDe709F2102306220921060314715629080e2FB77',
681+
'0xFb6916095cA1Df60bb79ce92cE3EA74c37c5d359'
682+
],
683+
31: [
684+
'0x42712D45473476B98452F434E72461577D686318',
685+
'0x27B1FdB04752BbC536007a920D24acB045561C26',
686+
'0x3599689e6292b81b2D85451025146515070129Bb',
687+
'0x52908400098527886E0F7030069857D2e4169EE7',
688+
'0x5aAeb6053F3e94c9b9A09F33669435E7EF1BEaEd',
689+
'0x66f9664F97F2b50f62d13eA064982F936DE76657',
690+
'0x8617e340b3D01fa5F11f306F4090Fd50e238070d',
691+
'0xDE709F2102306220921060314715629080e2Fb77',
692+
'0xFb6916095CA1dF60bb79CE92ce3Ea74C37c5D359',
693+
'0xd1220a0CF47c7B9Be7A2E6Ba89f429762E7b9adB',
694+
'0xdbF03B407C01E7cd3cbEa99509D93f8dDDc8C6fB'
695+
]
696+
}
697+
659698
describe('.toChecksumAddress()', function () {
660-
it('should work', function () {
661-
for (let i = 0; i < checksumAddresses.length; i++) {
662-
let tmp = checksumAddresses[i]
663-
assert.equal(ethUtils.toChecksumAddress(tmp.toLowerCase()), tmp)
664-
}
699+
describe("EIP55", function () {
700+
it('should work', function () {
701+
for (let i = 0; i < eip55ChecksumAddresses.length; i++) {
702+
let tmp = eip55ChecksumAddresses[i]
703+
assert.equal(ethUtils.toChecksumAddress(tmp.toLowerCase()), tmp)
704+
}
705+
})
706+
})
707+
708+
describe("EIP1191", function () {
709+
it('Should encode the example addresses correctly', function () {
710+
for (const [chainId, addresses] of Object.entries(eip1191ChecksummAddresses)) {
711+
for (const addr of addresses) {
712+
assert.equal(ethUtils.toChecksumAddress(addr.toLowerCase(), chainId), addr)
713+
}
714+
}
715+
})
665716
})
666717
})
667718

668719
describe('.isValidChecksumAddress()', function () {
669-
it('should return true', function () {
670-
for (let i = 0; i < checksumAddresses.length; i++) {
671-
assert.equal(ethUtils.isValidChecksumAddress(checksumAddresses[i]), true)
672-
}
720+
describe("EIP55", function () {
721+
it('should return true', function () {
722+
for (let i = 0; i < eip55ChecksumAddresses.length; i++) {
723+
assert.equal(ethUtils.isValidChecksumAddress(eip55ChecksumAddresses[i]), true)
724+
}
725+
})
726+
it('should validate', function () {
727+
assert.equal(ethUtils.isValidChecksumAddress('0x2f015c60e0be116b1f0cd534704db9c92118fb6a'), false)
728+
})
673729
})
674-
it('should validate', function () {
675-
assert.equal(ethUtils.isValidChecksumAddress('0x2f015c60e0be116b1f0cd534704db9c92118fb6a'), false)
730+
731+
describe("EIP1191", function () {
732+
it('Should return true for the example addresses', function () {
733+
for (const [chainId, addresses] of Object.entries(eip1191ChecksummAddresses)) {
734+
for (const addr of addresses) {
735+
assert.equal(ethUtils.isValidChecksumAddress(addr, chainId), true)
736+
}
737+
}
738+
})
739+
740+
it("Should return false for invalid cases", function () {
741+
// If we set the chain id, an EIP55 encoded address should be invalid
742+
for (let i = 0; i < eip55ChecksumAddresses.length; i++) {
743+
assert.equal(ethUtils.isValidChecksumAddress(eip55ChecksumAddresses[i], 1), false)
744+
}
745+
746+
assert.equal(ethUtils.isValidChecksumAddress('0x2f015c60e0be116b1f0cd534704db9c92118fb6a', 1), false)
747+
})
748+
749+
it("Should return false if the wrong chain id is used", function () {
750+
for (const [chainId, addresses] of Object.entries(eip1191ChecksummAddresses)) {
751+
for (const addr of addresses) {
752+
assert.equal(ethUtils.isValidChecksumAddress(addr, chainId + 1), false)
753+
}
754+
}
755+
})
676756
})
677757
})
678758

0 commit comments

Comments
 (0)