Skip to content
This repository was archived by the owner on Mar 5, 2025. It is now read-only.

Commit 280b8f0

Browse files
authored
create2 create (#7129)
* rlp lib * CREATE support * test data * contract deployment & addr test on node * local tests * updated tests * create2ContractAddress * test data * tests
1 parent 6454202 commit 280b8f0

File tree

7 files changed

+394
-11
lines changed

7 files changed

+394
-11
lines changed

packages/web3-eth-contract/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
"test:e2e:firefox": "npx cypress run --headless --browser firefox --env grep='ignore',invert=true"
4646
},
4747
"dependencies": {
48+
"@ethereumjs/rlp": "^5.0.2",
4849
"web3-core": "^4.4.0",
4950
"web3-errors": "^1.2.0",
5051
"web3-eth": "^4.7.0",

packages/web3-eth-contract/src/utils.ts

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ You should have received a copy of the GNU Lesser General Public License
1515
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
1616
*/
1717

18-
import { Web3ContractError } from 'web3-errors';
18+
import { RLP } from '@ethereumjs/rlp';
19+
import { InvalidAddressError, InvalidMethodParamsError, InvalidNumberError, Web3ContractError } from 'web3-errors';
1920
import {
2021
TransactionForAccessList,
2122
AbiFunctionFragment,
@@ -26,8 +27,10 @@ import {
2627
NonPayableCallOptions,
2728
PayableCallOptions,
2829
ContractOptions,
30+
Numbers,
2931
} from 'web3-types';
30-
import { isNullish, mergeDeep, isContractInitOptions } from 'web3-utils';
32+
import { isNullish, mergeDeep, isContractInitOptions, keccak256, toChecksumAddress, hexToNumber } from 'web3-utils';
33+
import { isAddress, isHexString } from 'web3-validator';
3134
import { encodeMethodABI } from './encoding.js';
3235
import { Web3ContractContext } from './types.js';
3336

@@ -210,3 +213,42 @@ export const getCreateAccessListParams = ({
210213

211214
return txParams;
212215
};
216+
217+
218+
export const createContractAddress = (from: Address, nonce: Numbers): Address => {
219+
if(!isAddress(from))
220+
throw new InvalidAddressError(`Invalid address given ${from}`);
221+
222+
let nonceValue = nonce;
223+
if(typeof nonce === "string" && isHexString(nonce))
224+
nonceValue = hexToNumber(nonce);
225+
else if(typeof nonce === "string" && !isHexString(nonce))
226+
throw new InvalidNumberError("Invalid nonce value format");
227+
228+
const rlpEncoded = RLP.encode(
229+
[from, nonceValue]
230+
);
231+
const result = keccak256(rlpEncoded);
232+
233+
const contractAddress = '0x'.concat(result.substring(26));
234+
235+
return toChecksumAddress(contractAddress);
236+
}
237+
238+
export const create2ContractAddress = (from: Address, salt: HexString, initCode: HexString): Address => {
239+
if(!isAddress(from))
240+
throw new InvalidAddressError(`Invalid address given ${from}`);
241+
242+
if(!isHexString(salt))
243+
throw new InvalidMethodParamsError(`Invalid salt value ${salt}`);
244+
245+
if(!isHexString(initCode))
246+
throw new InvalidMethodParamsError(`Invalid initCode value ${initCode}`);
247+
248+
const initCodeHash = keccak256(initCode);
249+
const initCodeHashPadded = initCodeHash.padStart(64, '0'); // Pad to 32 bytes (64 hex characters)
250+
const create2Params = ['0xff', from, salt, initCodeHashPadded].map(x => x.replace(/0x/, ''));
251+
const create2Address = `0x${ create2Params.join('')}`;
252+
253+
return toChecksumAddress(`0x${ keccak256(create2Address).slice(26)}`); // Slice to get the last 20 bytes (40 hex characters) & checksum
254+
}
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
/*
2+
This file is part of web3.js.
3+
4+
web3.js is free software: you can redistribute it and/or modify
5+
it under the terms of the GNU Lesser General Public License as published by
6+
the Free Software Foundation, either version 3 of the License, or
7+
(at your option) any later version.
8+
9+
web3.js is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
GNU Lesser General Public License for more details.
13+
14+
You should have received a copy of the GNU Lesser General Public License
15+
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
import { Numbers } from "web3-types";
19+
20+
export interface CreateTestData {
21+
address: string;
22+
input: {
23+
from: string;
24+
nonce: Numbers;
25+
};
26+
}
27+
28+
export const testData: CreateTestData[] = [
29+
{
30+
address: '0x0C1B54fb6fdf63DEe15e65CAdBA8F2e028E26Bd0',
31+
32+
input: {
33+
from: '0xe2597eb05cf9a87eb1309e86750c903ec38e527e',
34+
nonce: 0,
35+
}
36+
},
37+
{
38+
address: '0x0C1B54fb6fdf63DEe15e65CAdBA8F2e028E26Bd0',
39+
40+
input: {
41+
from: '0xe2597eb05cf9a87eb1309e86750c903ec38e527e',
42+
nonce: BigInt(0),
43+
}
44+
},
45+
{
46+
address: '0x0C1B54fb6fdf63DEe15e65CAdBA8F2e028E26Bd0',
47+
48+
input: {
49+
from: '0xe2597eb05cf9a87eb1309e86750c903ec38e527e',
50+
nonce: "0x0",
51+
}
52+
},
53+
{
54+
address: '0x3474627D4F63A678266BC17171D87f8570936622',
55+
56+
input: {
57+
from: '0xb2682160c482eb985ec9f3e364eec0a904c44c23',
58+
nonce: 10,
59+
}
60+
},
61+
62+
{
63+
address: '0x3474627D4F63A678266BC17171D87f8570936622',
64+
65+
input: {
66+
from: '0xb2682160c482eb985ec9f3e364eec0a904c44c23',
67+
nonce: "0xa",
68+
}
69+
},
70+
71+
{
72+
address: '0x3474627D4F63A678266BC17171D87f8570936622',
73+
74+
input: {
75+
from: '0xb2682160c482eb985ec9f3e364eec0a904c44c23',
76+
nonce: "0x0a",
77+
}
78+
},
79+
80+
{
81+
address: '0x271300790813f82638A8A6A8a86d65df6dF33c17',
82+
83+
input: {
84+
from: '0x8ba1f109551bd432803012645ac136ddd64dba72',
85+
nonce: "0x200",
86+
}
87+
},
88+
89+
{
90+
address: '0x271300790813f82638A8A6A8a86d65df6dF33c17',
91+
92+
input: {
93+
from: '0x8ba1f109551bd432803012645ac136ddd64dba72',
94+
nonce: "0x0200",
95+
}
96+
},
97+
98+
{
99+
address: '0x995C25706C407a1F1E84b3777775e3e619764933',
100+
101+
input: {
102+
from: '0x8ba1f109551bd432803012645ac136ddd64dba72',
103+
nonce: "0x1d",
104+
}
105+
},
106+
107+
{
108+
address: '0x995C25706C407a1F1E84b3777775e3e619764933',
109+
110+
input: {
111+
from: '0x8ba1f109551bd432803012645ac136ddd64dba72',
112+
nonce: "0x001d",
113+
}
114+
},
115+
116+
{
117+
address: '0x995C25706C407a1F1E84b3777775e3e619764933',
118+
119+
input: {
120+
from: '0x8ba1f109551bd432803012645ac136ddd64dba72',
121+
nonce: 29,
122+
}
123+
},
124+
125+
126+
{
127+
address: '0x0CcCC7507aEDf9FEaF8C8D731421746e16b4d39D',
128+
129+
input: {
130+
from: '0xc6af6e1a78a6752c7f8cd63877eb789a2adb776c',
131+
nonce: 0
132+
}
133+
},
134+
];
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
This file is part of web3.js.
3+
4+
web3.js is free software: you can redistribute it and/or modify
5+
it under the terms of the GNU Lesser General Public License as published by
6+
the Free Software Foundation, either version 3 of the License, or
7+
(at your option) any later version.
8+
9+
web3.js is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
GNU Lesser General Public License for more details.
13+
14+
You should have received a copy of the GNU Lesser General Public License
15+
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
import { Address, HexString } from "web3-types";
19+
20+
export interface Create2TestData {
21+
address: Address;
22+
salt: HexString;
23+
init_code: HexString;
24+
result: Address;
25+
}
26+
27+
export const create2TestData: Create2TestData[] = [
28+
{
29+
address: "0x0000000000000000000000000000000000000000",
30+
salt: "0x0000000000000000000000000000000000000000000000000000000000000000",
31+
init_code: "0x00",
32+
result: "0x4D1A2e2bB4F88F0250f26Ffff098B0b30B26BF38"
33+
},
34+
{
35+
address: "0xdeadbeef00000000000000000000000000000000",
36+
salt: "0x0000000000000000000000000000000000000000000000000000000000000000",
37+
init_code: "0x00",
38+
result: "0xB928f69Bb1D91Cd65274e3c79d8986362984fDA3"
39+
},
40+
{
41+
address: "0xdeadbeef00000000000000000000000000000000",
42+
salt: "0x000000000000000000000000feed000000000000000000000000000000000000",
43+
init_code: "0x00",
44+
result: "0xD04116cDd17beBE565EB2422F2497E06cC1C9833"
45+
},
46+
{
47+
address: "0x0000000000000000000000000000000000000000",
48+
salt: "0x0000000000000000000000000000000000000000000000000000000000000000",
49+
init_code: "0xdeadbeef",
50+
result: "0x70f2b2914A2a4b783FaEFb75f459A580616Fcb5e"
51+
},
52+
{
53+
address: "0x00000000000000000000000000000000deadbeef",
54+
salt: "0x00000000000000000000000000000000000000000000000000000000cafebabe",
55+
init_code: "0xdeadbeef",
56+
result: "0x60f3f640a8508fC6a86d45DF051962668E1e8AC7"
57+
},
58+
{
59+
address: "0x00000000000000000000000000000000deadbeef",
60+
salt: "0x00000000000000000000000000000000000000000000000000000000cafebabe",
61+
init_code: "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef",
62+
result: "0x1d8bfDC5D46DC4f61D6b6115972536eBE6A8854C"
63+
},
64+
{
65+
address: "0x0000000000000000000000000000000000000000",
66+
salt: "0x0000000000000000000000000000000000000000000000000000000000000000",
67+
init_code: "0x",
68+
result: "0xE33C0C7F7df4809055C3ebA6c09CFe4BaF1BD9e0"
69+
}
70+
];

packages/web3-eth-contract/test/integration/contract_deploy.test.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ along with web3.js. If not, see <http://www.gnu.org/licenses/>.
1616
*/
1717
import { Web3Eth } from 'web3-eth';
1818
import { FMT_BYTES, FMT_NUMBER } from 'web3-types';
19-
import { Contract } from '../../src';
19+
import { Contract, createContractAddress } from '../../src';
2020
import { sleep } from '../shared_fixtures/utils';
2121
import { ERC721TokenAbi, ERC721TokenBytecode } from '../shared_fixtures/build/ERC721Token';
2222
import { GreeterBytecode, GreeterAbi } from '../shared_fixtures/build/Greeter';
@@ -59,6 +59,18 @@ describe('contract', () => {
5959
sendOptions = { from: acc.address, gas: '1000000' };
6060
});
6161

62+
it('should get correct contract address before deploymet using CREATE', async () => {
63+
const nonce = await web3Eth.getTransactionCount(sendOptions.from as string);
64+
65+
// get contract address before deployment
66+
const address = createContractAddress(sendOptions.from as string, nonce);
67+
68+
const deployedContract = await contract.deploy(deployOptions).send(sendOptions);
69+
70+
expect(deployedContract).toBeDefined();
71+
expect(deployedContract.options.address).toEqual(address);
72+
});
73+
6274
afterAll(async () => {
6375
await closeOpenConnection(web3Eth);
6476
});

0 commit comments

Comments
 (0)