Added utility function to compute CREATE2 addresses (#697).

This commit is contained in:
Richard Moore 2020-01-03 18:20:15 -05:00
parent 7250cdcd31
commit f8087ae39c
No known key found for this signature in database
GPG Key ID: 665176BE8E9DC651
3 changed files with 108 additions and 2 deletions

@ -3,7 +3,7 @@
// We use this for base 36 maths
import BN from 'bn.js';
import { arrayify, stripZeros, hexlify } from './bytes';
import { arrayify, concat, stripZeros, hexlify } from './bytes';
import { BigNumber } from './bignumber';
import { keccak256 } from './keccak256';
import { encode } from './rlp';
@ -140,3 +140,47 @@ export function getContractAddress(transaction: { from: string, nonce: Arrayish
])).substring(26));
}
export type Create2Options = {
from: string,
salt: Arrayish,
initCode?: Arrayish,
initCodeHash?: Arrayish,
};
// See: https://eips.ethereum.org/EIPS/eip-1014
export function getCreate2Address(options: Create2Options): string {
let initCodeHash = options.initCodeHash;
if (options.initCode) {
if (initCodeHash) {
if (keccak256(options.initCode) !== initCodeHash) {
errors.throwError("initCode/initCodeHash mismatch", errors.INVALID_ARGUMENT, {
arg: "options", value: options
});
}
} else {
initCodeHash = keccak256(options.initCode);
}
}
if (!initCodeHash) {
errors.throwError("missing initCode or initCodeHash", errors.INVALID_ARGUMENT, {
arg: "options", value: options
});
}
const from = getAddress(options.from);
const salt = arrayify(options.salt);
if (salt.length !== 32) {
errors.throwError("invalid salt", errors.INVALID_ARGUMENT, {
arg: "options", value: options
});
}
return getAddress("0x" + keccak256(concat([
"0xff",
from,
salt,
initCodeHash
])).substring(26));
}

@ -1,7 +1,7 @@
'use strict';
import { AbiCoder, defaultAbiCoder, formatSignature, formatParamType, parseSignature, parseParamType } from './abi-coder';
import { getAddress, getContractAddress, getIcapAddress } from './address';
import { getAddress, getContractAddress, getCreate2Address, getIcapAddress } from './address';
import * as base64 from './base64';
import { BigNumber, bigNumberify } from './bignumber';
import { arrayify, concat, hexDataSlice, hexDataLength, hexlify, hexStripZeros, hexZeroPad, isHexString, joinSignature, padZeros, splitSignature, stripZeros } from './bytes';
@ -103,6 +103,7 @@ export {
getAddress,
getIcapAddress,
getContractAddress,
getCreate2Address,
formatEther,
parseEther,

@ -36,3 +36,64 @@ describe('Checksum and ICAP address generation', function() {
});
});
});
describe("Create2 Address Generation", function() {
var tests = [
{
name: "Example 0",
from: "0x0000000000000000000000000000000000000000",
salt: "0x0000000000000000000000000000000000000000000000000000000000000000",
initCode: "0x00",
expected: "0x4D1A2e2bB4F88F0250f26Ffff098B0b30B26BF38"
},
{
name: "Example 1",
from: "0xdeadbeef00000000000000000000000000000000",
salt: "0x0000000000000000000000000000000000000000000000000000000000000000",
initCode: "0x00",
expected: "0xB928f69Bb1D91Cd65274e3c79d8986362984fDA3"
},
{
name: "Example 2",
from: "0xdeadbeef00000000000000000000000000000000",
salt: "0x000000000000000000000000feed000000000000000000000000000000000000",
initCode: "0x00",
expected: "0xD04116cDd17beBE565EB2422F2497E06cC1C9833"
},
{
name: "Example 3",
from: "0x0000000000000000000000000000000000000000",
salt: "0x0000000000000000000000000000000000000000000000000000000000000000",
initCode: "0xdeadbeef",
expected: "0x70f2b2914A2a4b783FaEFb75f459A580616Fcb5e"
},
{
name: "Example 4",
from: "0x00000000000000000000000000000000deadbeef",
salt: "0x00000000000000000000000000000000000000000000000000000000cafebabe",
initCode: "0xdeadbeef",
expected: "0x60f3f640a8508fC6a86d45DF051962668E1e8AC7"
},
{
name: "Example 5",
from: "0x00000000000000000000000000000000deadbeef",
salt: "0x00000000000000000000000000000000000000000000000000000000cafebabe",
initCode: "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef",
expected: "0x1d8bfDC5D46DC4f61D6b6115972536eBE6A8854C"
},
{
name: "Example 6",
from: "0x0000000000000000000000000000000000000000",
salt: "0x0000000000000000000000000000000000000000000000000000000000000000",
initCode: "0x",
expected: "0xE33C0C7F7df4809055C3ebA6c09CFe4BaF1BD9e0"
},
];
tests.forEach(function(test) {
it("correctly computes the Create2 address - " + test.name, function() {
const address = ethers.utils.getCreate2Address(test);
assert.equal(address, test.expected, "correctly computes Create2 address");
});
});
});