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

Commit

Permalink
Merge pull request #204 from ethereumjs/eip1191
Browse files Browse the repository at this point in the history
Implement EIP1191
  • Loading branch information
alcuadrado authored Jun 28, 2019
2 parents a7bfe26 + beecf2d commit 3b10850
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 35 deletions.
46 changes: 27 additions & 19 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ ___

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

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

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

**Returns:** `any`
(Array|String|null)
(Array\|String\|null)

___
<a id="buffertohex"></a>
Expand All @@ -236,7 +236,7 @@ ___

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

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

**Parameters:**

Expand Down Expand Up @@ -376,7 +376,7 @@ ___

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

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

Generates an address of a newly created contract.

Expand All @@ -396,7 +396,7 @@ ___

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

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

Generates an address for a contract created using CREATE2.

Expand Down Expand Up @@ -436,7 +436,7 @@ ___

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

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

Converts a public key to the Ethereum format.

Expand All @@ -455,7 +455,7 @@ ___

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

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

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

Expand Down Expand Up @@ -491,17 +491,20 @@ ___

### `<Const>` isValidChecksumAddress

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

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

Checks if the address is a valid checksummed address.

See toChecksumAddress' documentation for details about the eip1191ChainId parameter.

**Parameters:**

| Name | Type |
| ------ | ------ |
| address | `string` |
| `Optional` eip1191ChainId | `undefined` \| `number` |

**Returns:** `boolean`

Expand All @@ -512,7 +515,7 @@ ___

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

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

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

Expand All @@ -531,7 +534,7 @@ ___

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

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

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

Expand Down Expand Up @@ -632,7 +635,7 @@ ___

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

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

Returns the ethereum address of a given private key.

Expand All @@ -651,7 +654,7 @@ ___

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

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

Returns the ethereum public key of a given private key.

Expand All @@ -670,7 +673,7 @@ ___

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

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

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

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

**Returns:** `any`
(Buffer|Array)
(Buffer\|Array)

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

**Returns:** `any`
(Buffer|Array)
(Buffer\|Array)

___
<a id="sha256"></a>
Expand Down Expand Up @@ -808,17 +811,22 @@ ___

### `<Const>` toChecksumAddress

**toChecksumAddress**(address: *`string`*): `string`
**toChecksumAddress**(address: *`string`*, eip1191ChainId?: *`undefined` \| `number`*): `string`

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

Returns a checksummed address.

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.

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.

**Parameters:**

| Name | Type |
| ------ | ------ |
| address | `string` |
| `Optional` eip1191ChainId | `undefined` \| `number` |

**Returns:** `string`

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

**Returns:** `any`
(Buffer|Array|String)
(Buffer\|Array\|String)

___
<a id="zeroaddress"></a>
Expand Down
20 changes: 16 additions & 4 deletions src/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,20 @@ export const isZeroAddress = function(address: string): boolean {

/**
* Returns a checksummed address.
*
* 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.
*
* 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.
*/
export const toChecksumAddress = function(address: string): string {
export const toChecksumAddress = function(address: string, eip1191ChainId?: number): string {
address = ethjsUtil.stripHexPrefix(address).toLowerCase()
const hash = keccak(address).toString('hex')

const prefix = eip1191ChainId !== undefined ? eip1191ChainId.toString() + '0x' : ''

const hash = keccak(prefix + address).toString('hex')
let ret = '0x'

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

/**
* Checks if the address is a valid checksummed address.
*
* See toChecksumAddress' documentation for details about the eip1191ChainId parameter.
*/
export const isValidChecksumAddress = function(address: string): boolean {
return isValidAddress(address) && toChecksumAddress(address) === address
export const isValidChecksumAddress = function(address: string, eip1191ChainId?: number): boolean {
return isValidAddress(address) && toChecksumAddress(address, eip1191ChainId) === address
}

/**
Expand Down
104 changes: 92 additions & 12 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -642,7 +642,7 @@ describe('isValidSignature', function () {
// FIXME: add homestead test
})

const checksumAddresses = [
const eip55ChecksumAddresses = [
// All caps
'0x52908400098527886E0F7030069857D2E4169EE7',
'0x8617E340B3D01FA5F11F306F4090FD50E238070D',
Expand All @@ -656,23 +656,103 @@ const checksumAddresses = [
'0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb'
]

const eip1191ChecksummAddresses = {
1: [
'0x88021160c5C792225E4E5452585947470010289d',
'0x27b1FdB04752bBc536007a920D24ACB045561c26',
'0x52908400098527886e0f7030069857D2e4169EE7',
'0x5aaeB6053f3E94C9b9A09f33669435e7Ef1bEAed',
'0x8617E340b3d01FA5F11F306f4090FD50E238070d',
'0xd1220a0CF47C7B9Be7A2E6ba89F429762E7B9Adb',
'0xdBf03b407c01e7cD3CBea99509d93f8dDDC8C6fB',
'0xDe709F2102306220921060314715629080E2fb77',
'0xfb6916095Ca1dF60bB79cE92ce3ea74C37c5D359',
],
30: [
'0x6549F4939460DE12611948B3F82B88C3C8975323',
'0x27b1FdB04752BBc536007A920D24ACB045561c26',
'0x3599689E6292B81B2D85451025146515070129Bb',
'0x52908400098527886E0F7030069857D2E4169ee7',
'0x5aaEB6053f3e94c9b9a09f33669435E7ef1bEAeD',
'0x8617E340b3D01Fa5f11f306f4090fd50E238070D',
'0xD1220A0Cf47c7B9BE7a2e6ba89F429762E7B9adB',
'0xDBF03B407c01E7CD3cBea99509D93F8Dddc8C6FB',
'0xDe709F2102306220921060314715629080e2FB77',
'0xFb6916095cA1Df60bb79ce92cE3EA74c37c5d359'
],
31: [
'0x42712D45473476B98452F434E72461577D686318',
'0x27B1FdB04752BbC536007a920D24acB045561C26',
'0x3599689e6292b81b2D85451025146515070129Bb',
'0x52908400098527886E0F7030069857D2e4169EE7',
'0x5aAeb6053F3e94c9b9A09F33669435E7EF1BEaEd',
'0x66f9664F97F2b50f62d13eA064982F936DE76657',
'0x8617e340b3D01fa5F11f306F4090Fd50e238070d',
'0xDE709F2102306220921060314715629080e2Fb77',
'0xFb6916095CA1dF60bb79CE92ce3Ea74C37c5D359',
'0xd1220a0CF47c7B9Be7A2E6Ba89f429762E7b9adB',
'0xdbF03B407C01E7cd3cbEa99509D93f8dDDc8C6fB'
]
}

describe('.toChecksumAddress()', function () {
it('should work', function () {
for (let i = 0; i < checksumAddresses.length; i++) {
let tmp = checksumAddresses[i]
assert.equal(ethUtils.toChecksumAddress(tmp.toLowerCase()), tmp)
}
describe("EIP55", function () {
it('should work', function () {
for (let i = 0; i < eip55ChecksumAddresses.length; i++) {
let tmp = eip55ChecksumAddresses[i]
assert.equal(ethUtils.toChecksumAddress(tmp.toLowerCase()), tmp)
}
})
})

describe("EIP1191", function () {
it('Should encode the example addresses correctly', function () {
for (const [chainId, addresses] of Object.entries(eip1191ChecksummAddresses)) {
for (const addr of addresses) {
assert.equal(ethUtils.toChecksumAddress(addr.toLowerCase(), chainId), addr)
}
}
})
})
})

describe('.isValidChecksumAddress()', function () {
it('should return true', function () {
for (let i = 0; i < checksumAddresses.length; i++) {
assert.equal(ethUtils.isValidChecksumAddress(checksumAddresses[i]), true)
}
describe("EIP55", function () {
it('should return true', function () {
for (let i = 0; i < eip55ChecksumAddresses.length; i++) {
assert.equal(ethUtils.isValidChecksumAddress(eip55ChecksumAddresses[i]), true)
}
})
it('should validate', function () {
assert.equal(ethUtils.isValidChecksumAddress('0x2f015c60e0be116b1f0cd534704db9c92118fb6a'), false)
})
})
it('should validate', function () {
assert.equal(ethUtils.isValidChecksumAddress('0x2f015c60e0be116b1f0cd534704db9c92118fb6a'), false)

describe("EIP1191", function () {
it('Should return true for the example addresses', function () {
for (const [chainId, addresses] of Object.entries(eip1191ChecksummAddresses)) {
for (const addr of addresses) {
assert.equal(ethUtils.isValidChecksumAddress(addr, chainId), true)
}
}
})

it("Should return false for invalid cases", function () {
// If we set the chain id, an EIP55 encoded address should be invalid
for (let i = 0; i < eip55ChecksumAddresses.length; i++) {
assert.equal(ethUtils.isValidChecksumAddress(eip55ChecksumAddresses[i], 1), false)
}

assert.equal(ethUtils.isValidChecksumAddress('0x2f015c60e0be116b1f0cd534704db9c92118fb6a', 1), false)
})

it("Should return false if the wrong chain id is used", function () {
for (const [chainId, addresses] of Object.entries(eip1191ChecksummAddresses)) {
for (const addr of addresses) {
assert.equal(ethUtils.isValidChecksumAddress(addr, chainId + 1), false)
}
}
})
})
})

Expand Down

0 comments on commit 3b10850

Please sign in to comment.