Skip to content

Instantly share code, notes, and snippets.

@santteegt
Last active August 31, 2022 21:49
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save santteegt/f0d3b93b383c4c1ba047a6046cd3a2bb to your computer and use it in GitHub Desktop.
Save santteegt/f0d3b93b383c4c1ba047a6046cd3a2bb to your computer and use it in GitHub Desktop.
Calculate ProxyAddress from a Given CREATE2 call - Example using GnosisSafe
// This script assume using the GnosisSafe & GnosisSafeProxyFactory from here
// https://github.com/gnosis/safe-contracts/blob/v1.2.0/contracts/proxies/GnosisSafeProxyFactory.sol
// safe -> https://github.com/gnosis/safe-contracts/blob/v1.2.0/contracts/GnosisSafe.sol
import { ethers } from 'ethers';
import Web3 from 'web3';
import * as ethUtil from 'ethereumjs-util';
import abi from 'ethereumjs-abi';
const rpcUrl = ''; // Fill your RPC URI
const web3 = web3 = new Web3(new Web3.providers.HttpProvider(rpcUrl));
const safeProxyFactoryAddress = '0x76E2cFc1F5Fa8F6a5b3fC4c8F4788F0116861F9B';
const safeMasterCopyAddress = '0x6851d6fdfafd08c0295c392436245e5bc78b0185';
// contract for deploying new safes
const safeProxyFactory = new web3.eth.Contract(
safeProxyFactoryAbi,
safeProxyFactoryAddress,
);
const safe = new web3.eth.Contract(
safeMasterCopyAbi,
safeMasterCopyAddress,
);
const saltNonce = (new Date().getTime() / 1000).toFixed();
const setupData = safe.methods
.setup(
[delegateAddress, minionAddress], // owners
threshold, // signing threshol d
Address0, // to - Contract address for optional delegate call.
"0x", // data - Data payload for optional delegate call.
Address0, // fallbackHandler
Address0, // paymentToken
0, // payment
Address0, // paymentReceiver
)
.encodeABI();
const proxyCreationCode = await safeProxyFactory.methods
.proxyCreationCode()
.call();
// Alternative 1: Using ethereumjs-abi library
// ========================================================
// Check GnosisSafeProxyFactory.deployProxyWithNonce method
const encodedNonce = abi
.rawEncode(['uint256'], [saltNonce])
.toString('hex');
const salt = ethUtil.keccak256(
`0x${ethUtil.keccak256(setupData).toString('hex') + encodedNonce}`,
);
const constructorData = abi
.rawEncode(['address'], [safeMasterCopyAddress])
.toString('hex');
const initCode = proxyCreationCode + constructorData;
const contractAddress = `0x${ethUtil
.generateAddress2(
safeProxyFactory.options.address,
salt,
initCode,
)
.toString('hex')}`;
console.log('Predicted safe address using ethereumjs-util', contractAddress);
// Alternative 2: Using ethers library
// ========================================================
const salt2 = ethers.utils.solidityKeccak256(
['bytes32', 'uint256'],
[ethers.utils.solidityKeccak256(['bytes'], [setupData]), saltNonce],
);
// does not work with web3.eth.abi.encodeParameters as it packed encode with additional data like length ?
const initCode2 = ethers.utils.solidityPack(
['bytes', 'uint256'],
[proxyCreationCode, safeMasterCopyAddress],
);
const contractAddress2 = ethers.utils.getCreate2Address(
safeProxyFactory.options.address,
salt2,
ethers.utils.keccak256(initCode2),
);
console.log('Predicted safe address using ethers', contractAddress2);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment