[Deployment] Using create2 from the SystemContractsCaller #363
-
EnvironmentTestnet zkSolc Version1.3.23 zksync-web3 Versionethers-v6 Hardhat.config.tsrequire('dotenv').config()
import { HardhatUserConfig } from 'hardhat/config';
import '@typechain/hardhat';
import 'hardhat-abi-exporter';
import '@matterlabs/hardhat-zksync-node';
import '@matterlabs/hardhat-zksync-deploy';
import '@matterlabs/hardhat-zksync-solc';
import "@matterlabs/hardhat-zksync-ethers";
import '@matterlabs/hardhat-zksync-verify';
import "@matterlabs/hardhat-zksync-chai-matchers";
const optimizerDisabled = process.env.OPTIMIZER_DISABLED
const config: HardhatUserConfig = {
solidity: {
compilers: [
{
version: '0.8.17',
settings: {
optimizer: {
enabled: !optimizerDisabled,
runs: 200
}
},
},
],
},
zksolc: {
version: 'latest',
settings: {
// find all available options in the official documentation
// https://era.zksync.io/docs/tools/hardhat/hardhat-zksync-solc.html#configuration
},
},
defaultNetwork: 'zkSyncTestnet',
networks: {
zkSyncTestnet: {
url: "https://sepolia.era.zksync.dev",
ethNetwork: "sepolia",
zksync: true,
verifyURL: "https://explorer.sepolia.era.zksync.dev/contract_verification",
chainId: 324,
},
zkSyncMainnet: {
url: "https://mainnet.era.zksync.io",
ethNetwork: "mainnet",
zksync: true,
verifyURL: "https://zksync2-mainnet-explorer.zksync.io/contract_verification",
chainId: 300,
},
dockerizedNode: {
url: "http://localhost:3050",
ethNetwork: "http://localhost:8545",
zksync: true,
},
inMemoryNode: {
url: "http://127.0.0.1:8011",
ethNetwork: "", // in-memory node doesn't support eth node; removing this line will cause an error
zksync: true,
},
hardhat: {
zksync: true,
},
},
etherscan: {
apiKey: {
mainnet: process.env.ETHERSCAN_API_KEY ?? '',
}
},
abiExporter: {
path: './abis',
runOnCompile: true,
clear: true,
flat: true,
only: [
'SmartAccount',
'ERC6551zkSyncRegistry',
],
},
};
export default config; Deployment Script (WITHOUT PRIVATE KEY)import { Wallet, Provider, Contract, utils } from "zksync-ethers";
import { ethers } from "ethers";
import * as hre from "hardhat";
import { Deployer } from "@matterlabs/hardhat-zksync-deploy";
import { getProvider, getWallet } from '../utils/utils';
import DeployAll from './DeployAll';
import DeployERC20Mock from './ERC20Mock';
import DeployNFTMock from './NFTMock';
const salt = ethers.encodeBytes32String('');
const input = ethers.encodeBytes32String('');
const chainId = 1;
let _smartAccountHash: Uint8Array;
let _nftMockAddress: string = '';
let _erc20MockAddress: string = '';
let _zkSyncRegistry: Contract;
let _nftMock: Contract;
let _erc20Mock: Contract;
let _provider: Provider;
let _wallet: Wallet;
let _walletAddress: string;
let _deployer: Deployer;
const calculateAccountAddress = async () => {
const newAccountAddress = utils.create2Address(
_walletAddress,
_smartAccountHash,
salt,
input,
);
return newAccountAddress;
};
export default async function () {
_provider = getProvider();
_wallet = getWallet();
_deployer = new Deployer(hre, _wallet);
_walletAddress = _wallet.address;
const { zkSyncRegistry, smartAccountHash } = await DeployAll();
_zkSyncRegistry = zkSyncRegistry;
_smartAccountHash = smartAccountHash;
console.log(`Deploying Mock ERC20 Token...`);
const { contract: erc20Mock, address: erc20MockAddress } = await DeployERC20Mock();
_erc20Mock = erc20Mock;
_erc20MockAddress = erc20MockAddress;
console.log(`Deploying Mock NFT Contract...`);
const { contract: nftMock, address: nftMockAddress } = await DeployNFTMock();
_nftMock = nftMock;
_nftMockAddress = nftMockAddress;
console.log(`Minting Mock Tokens...`);
await _erc20Mock.mint(_walletAddress, 10000n).then(tx => tx.wait());
const tokenBalance = await _erc20Mock.balanceOf(_walletAddress);
console.log(`Token Balance: ${tokenBalance}`);
console.log(`Minting Mock NFT...`);
const nftBalance = await _nftMock.balanceOf(_walletAddress);
await _nftMock.mint(_walletAddress, nftBalance + 1n).then(tx => tx.wait());
const newNftBalance = await _nftMock.balanceOf(_walletAddress);
console.log(`New NFT Balance: ${newNftBalance}`);
// Calculate Expected Account Address via Registry
const tokenId = 1;
const newAccountAddress = await calculateAccountAddress();
console.log(`Expected Account Address: ${newAccountAddress}`);
// Try to Create SmartAccount by calling the Registry directly
const txReceipt = await _zkSyncRegistry.createAccount(
_smartAccountHash,
salt,
chainId,
_nftMockAddress,
tokenId,
).then(tx => tx.wait());
console.log(`txReceipt = ${txReceipt}`);
} Package.json{
"name": "zksync-create2",
"version": "1.0.0",
"main": "index.js",
"repository": "https://github.com/Charged-Particles/cpu-v2.git",
"author": "Firma Lux, Inc. <charged.fi>",
"license": "MIT",
"scripts": {
"reinstall": "yarn clean && rm -rf node_modules && rm -f yarn.lock && yarn",
"clean": "yarn clean-build && yarn clean-test && hardhat clean",
"clean-test": "rm -rf test-results.xml coverage coverage.json test-results.xml",
"clean-build": "rm -rf abis build cache-zk typechain-types",
"compile": "hardhat compile --show-stack-traces --max-memory 8192",
"test": "export IS_TEST=true && yarn clean-test && hardhat test --show-stack-traces --network hardhat",
"watch-test": "hardhat watch test",
"coverage": "yarn clean-test && hardhat --show-stack-traces coverage --temp coverage_build && yarn clean-test",
"gas": "REPORT_GAS=true yarn test",
"deploy": "hardhat deploy-zksync --script DeployAll.ts --network",
"deploy-test": "hardhat deploy-zksync --script ZkSepoliaTest.ts --network"
},
"devDependencies": {
"@matterlabs/hardhat-zksync-chai-matchers": "^1.2.1",
"@matterlabs/hardhat-zksync-deploy": "^1.1.2",
"@matterlabs/hardhat-zksync-ethers": "^1.0.0",
"@matterlabs/hardhat-zksync-node": "^1.0.1",
"@matterlabs/hardhat-zksync-solc": "^1.0.6",
"@matterlabs/hardhat-zksync-verify": "^1.2.2",
"@matterlabs/zksync-contracts": "^0.6.1",
"@nomicfoundation/hardhat-chai-matchers": "^2.0.4",
"@nomicfoundation/hardhat-verify": "^2.0.0",
"@nomiclabs/hardhat-ethers": "^2.2.3",
"@openzeppelin/contracts": "4.6.0",
"@openzeppelin/contracts-upgradeable": "4.6.0",
"@typechain/ethers-v6": "^0.4.3",
"@typechain/hardhat": "^8.0.3",
"@types/chai": "^4.3.4",
"@types/mocha": "^10.0.1",
"@types/node": "^20.11.16",
"chai": "^4.3.7",
"dotenv": "^16.0.3",
"ethers": "^6.10.0",
"hardhat": "^2.12.4",
"hardhat-abi-exporter": "^2.10.1",
"mocha": "^10.2.0",
"ts-node": "^10.9.1",
"typechain": "^8.3.1",
"typescript": "^4.9.5",
"zksync-ethers": "^6.2.0"
}
} Contract Code// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
import {IERC6551zkSyncRegistry} from "./interfaces/IERC6551zkSyncRegistry.sol";
import "@matterlabs/zksync-contracts/l2/system-contracts/Constants.sol";
import "@matterlabs/zksync-contracts/l2/system-contracts/libraries/SystemContractsCaller.sol";
contract ERC6551zkSyncRegistry is IERC6551zkSyncRegistry {
function createAccount(
bytes32 bytecodeHash,
bytes32 salt,
uint256 chainId,
address tokenContract,
uint256 tokenId
) external returns (address accountAddress) {
address newAccount = account(bytecodeHash, salt, chainId, tokenContract, tokenId);
if (newAccount.code.length == 0) {
(bool success, bytes memory returnData) = SystemContractsCaller
.systemCallWithReturndata(
uint32(gasleft()),
address(DEPLOYER_SYSTEM_CONTRACT),
uint128(0),
abi.encodeCall(
DEPLOYER_SYSTEM_CONTRACT.create2,
(salt, bytecodeHash, abi.encode(chainId, tokenContract, tokenId))
)
);
if (!success) { revert AccountCreationFailed(); }
emit ERC6551AccountCreated(newAccount, bytecodeHash, salt, chainId, tokenContract, tokenId);
accountAddress = abi.decode(returnData, (address));
} else {
accountAddress = newAccount;
}
}
function account(
bytes32 bytecodeHash,
bytes32 salt,
uint256 chainId,
address tokenContract,
uint256 tokenId
) public returns (address accountAddress) {
(bool success, bytes memory returnData) = SystemContractsCaller
.systemCallWithReturndata(
uint32(gasleft()),
address(DEPLOYER_SYSTEM_CONTRACT),
uint128(0),
abi.encodeCall(
DEPLOYER_SYSTEM_CONTRACT.getNewAddressCreate2,
(msg.sender, bytecodeHash, salt, abi.encode(chainId, tokenContract, tokenId))
)
);
if (!success) { revert AccountComputeFailed(); }
accountAddress = abi.decode(returnData, (address));
}
} Does this work on other EVMs? (If yes, please list at least 1 of them)No, it is zkSync Era specific Description of What Your Contract DoesA Factory that deploys ERC6551 Account Contracts Repo Link (Optional)https://github.com/Charged-Particles/zksync-create2 Additional DetailsFully working repo with the issue isolated. Please let me know what I am doing wrong! |
Beta Was this translation helpful? Give feedback.
Answered by
dutterbutter
Mar 22, 2024
Replies: 4 comments 4 replies
This comment was marked as spam.
This comment was marked as spam.
This comment was marked as spam.
This comment was marked as spam.
This comment was marked as spam.
This comment was marked as spam.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@robsecord sorry for the delay here friend.
Can you add the is-system flag to true in your hardhat config.
isSystem: true,
. Anytime you are interacting with a system contract this flag needs to be present in your config. Please let me know if that helps 🚀