Skip to content

Commit

Permalink
Update deploy scripts with more checks
Browse files Browse the repository at this point in the history
  • Loading branch information
ignasirv committed Oct 31, 2024
1 parent 53d72f7 commit d5b0cc1
Show file tree
Hide file tree
Showing 3 changed files with 163 additions and 31 deletions.
15 changes: 15 additions & 0 deletions deployment/testnet/prepareTestnet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,21 @@ async function main() {
}

deployParameters.polTokenAddress = polTokenContract.target;

/*
* Deployment gasToken address
* A erc20 is deployed in this testnet in case it's wanted to deploy a rollup that uses this token as the gas token
*/
const gasTokenName = "Gas Token";
const gasTokenSymbol = "GAS";

const gasTokenFactory = await ethers.getContractFactory("ERC20", deployer);
const gasTokenContract = await gasTokenFactory.deploy(gasTokenName, gasTokenSymbol);
await gasTokenContract.waitForDeployment();
deployParameters.gasTokenAddress = gasTokenContract.target;
console.log("#######################\n");
console.log("gas token deployed to:", gasTokenContract.target);

fs.writeFileSync(pathDeployParameters, JSON.stringify(deployParameters, null, 1));
}

Expand Down
23 changes: 20 additions & 3 deletions deployment/v2/4_createRollup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import "../helpers/utils";
import updateVanillaGenesis from "./utils/updateVanillaGenesis";

const pathOutputJson = path.join(__dirname, "./create_rollup_output.json");
const deployParameters = require("./deploy_parameters.json");

import {
PolygonRollupManager,
Expand Down Expand Up @@ -262,12 +263,19 @@ async function main() {
) as PolygonZkEVMBridgeV2;
if (
createRollupParameters.gasTokenAddress &&
createRollupParameters.gasTokenAddress != "" &&
createRollupParameters.gasTokenAddress != ethers.ZeroAddress
createRollupParameters.gasTokenAddress !== "" &&
createRollupParameters.gasTokenAddress !== ethers.ZeroAddress
) {
// If gas token address is "deployed" use the one from deploy parameters, erc20 deployed at prepare testnet script
if(createRollupParameters.gasTokenAddress == "deployed") {
createRollupParameters.gasTokenAddress = deployParameters.gasTokenAddress;
}
// Get token metadata
gasTokenMetadata = await polygonZkEVMBridgeContract.getTokenMetadata(createRollupParameters.gasTokenAddress);

// If gas token metadata includes `0x124e4f545f56414c49445f454e434f44494e47 (NOT_VALID_ENCODING)` means there is no erc20 token deployed at the selected gas token network
if(gasTokenMetadata.includes("124e4f545f56414c49445f454e434f44494e47")) {
throw new Error(`Invalid gas token address, no ERC20 token deployed at the selected gas token network ${createRollupParameters.gasTokenAddress}`);
}
const wrappedData = await polygonZkEVMBridgeContract.wrappedTokenToTokenInfo(
createRollupParameters.gasTokenAddress
);
Expand Down Expand Up @@ -382,6 +390,15 @@ async function main() {
globalExitRootUpdater: sovereignParams.globalExitRootUpdater,
};
genesis = await updateVanillaGenesis(genesis, chainID, initializeParams);
// Add weth address to deployment output if gas token address is provided and sovereignWETHAddress is not provided
if ( gasTokenAddress !== ethers.ZeroAddress &&
ethers.isAddress(gasTokenAddress) &&
(sovereignParams.sovereignWETHAddress === ethers.ZeroAddress || !ethers.isAddress(sovereignParams.sovereignWETHAddress))) {
const wethObject = genesis.genesis.find(function (obj) {
return obj.contractName == "WETH";
});
outputJson.WETHAddress = wethObject.address;
}
} else {
if (consensusContract === "PolygonPessimisticConsensus") {
// Add the first batch of the created rollup
Expand Down
156 changes: 128 additions & 28 deletions deployment/v2/utils/updateVanillaGenesis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,13 @@ async function updateVanillaGenesis(genesis, chainID, initializeParams) {
bridgeProxy.contractName = bridgeContractName + " proxy";
bridgeProxy.storage = await zkEVMDB2.dumpStorage(bridgeProxy.address);
// If bridge initialized with a zero sovereign weth address and a non zero gas token, we should add created erc20 weth contract to the genesis
if (gasTokenAddress !== ethers.ZeroAddress && sovereignWETHAddress === ethers.ZeroAddress) {
const wethAddress = padTo20Bytes(
let wethAddress;
if (
gasTokenAddress !== ethers.ZeroAddress &&
ethers.isAddress(gasTokenAddress) &&
(sovereignWETHAddress === ethers.ZeroAddress || !ethers.isAddress(sovereignWETHAddress))
) {
wethAddress = padTo20Bytes(
bridgeProxy.storage["0x000000000000000000000000000000000000000000000000000000000000006f"]
);
const wethGenesis = {
Expand All @@ -199,38 +204,121 @@ async function updateVanillaGenesis(genesis, chainID, initializeParams) {
return acc;
}, {});

// Sanity check bridge storage
if (rollupID !== 0) {
// RollupID value is stored at position 68 with globalExitRootManager address. Slice from byte 2 to 2-8 to get the rollupID
expect(
bridgeProxy.storage["0x0000000000000000000000000000000000000000000000000000000000000068"].slice(
2 + 54,
2 + 54 + 8
)
).to.include(rollupID.toString(16));
}
if (gasTokenAddress !== ethers.ZeroAddress) {
// CHECK BRIDGE PROXY STORAGE
// Storage value pointing bridge implementation
expect(bridgeProxy.storage["0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc"]).to.include(
oldBridge.address.toLowerCase().slice(2)
);

// Storage value of proxyAdmin
const proxyAdminObject = genesis.genesis.find(function (obj) {
return obj.contractName == "ProxyAdmin";
});
expect(bridgeProxy.storage["0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103"]).to.include(
proxyAdminObject.address.toLowerCase().slice(2)
);

// Storage value of bridge manager
expect(bridgeProxy.storage["0x00000000000000000000000000000000000000000000000000000000000000a3"]).to.include(
bridgeManager.toLowerCase().slice(2)
);

// Storage value for the _initialized uint8 variable of Initializable.sol contract, incremented each time the contract is successfully initialized. It also stores the _initializing param set to true when an initialization function is being executed, and it reverts to false once the initialization completed.
expect(bridgeProxy.storage["0x0000000000000000000000000000000000000000000000000000000000000000"]).to.equal(
"0x0000000000000000000000000000000000000000000000000000000000000001"
);

// Storage value for the _status variable of ReentrancyGuardUpgradeable contract. Tracks the current "status" of the contract to enforce the non-reentrant behavior. Default value is 1 (_NOT_ENTERED)
expect(bridgeProxy.storage["0x0000000000000000000000000000000000000000000000000000000000000001"]).to.equal(
"0x0000000000000000000000000000000000000000000000000000000000000001"
);

// Storage value for global exit root manager (proxy) address
expect(bridgeProxy.storage["0x0000000000000000000000000000000000000000000000000000000000000068"]).to.include(
gerProxy.address.toLowerCase().slice(2)
);

// Storage value for rollup/network id
// RollupID value is stored at position 68 with globalExitRootManager address. Slice from byte 2 to 2-8 to get the rollupID
expect(
bridgeProxy.storage["0x0000000000000000000000000000000000000000000000000000000000000068"].slice(
2 + 54,
2 + 54 + 8
)
).to.include(rollupID.toString(16));

// Storage value for gas token address
if (gasTokenAddress !== ethers.ZeroAddress && ethers.isAddress(gasTokenAddress)) {
expect(
ethers.toBigInt(bridgeProxy.storage["0x000000000000000000000000000000000000000000000000000000000000006d"])
).to.equal(
ethers.toBigInt(`${ethers.toBeHex(gasTokenNetwork)}${gasTokenAddress.replace(/^0x/, "")}`.toLowerCase())
);
if (ethers.isAddress(sovereignWETHAddress) && sovereignWETHAddress !== ethers.ZeroAddress) {
// Storage value for sovereignWETH address (ony if network with native gas token) and sovereignWethAddress is set
expect(
bridgeProxy.storage["0x000000000000000000000000000000000000000000000000000000000000006f"]
).to.include(sovereignWETHAddress.toLowerCase().slice(2));

// Storage address for sovereignWETHAddressIsNotMintable mapping
// To get the key we encode the key of the mapping with the position in the mapping
if (sovereignWETHAddressIsNotMintable) {
const mappingSlot = 162; // Slot of the mapping in the bridge contract
const key = ethers.keccak256(ethers.AbiCoder.defaultAbiCoder().encode(["address", "uint256"], [sovereignWETHAddress, mappingSlot]));
expect(
bridgeProxy.storage[key]
).to.equal("0x0000000000000000000000000000000000000000000000000000000000000001");
}
} else {
// Storage value for WETH address (ony if network with native gas token), deployed at bridge initialization
expect(
bridgeProxy.storage["0x000000000000000000000000000000000000000000000000000000000000006f"]
).to.include(wethAddress.toLowerCase().slice(2));

// CHECK WETH STORAGE
const wethOject = genesis.genesis.find(function (obj) {
return obj.contractName == "WETH";
});

// Storage for erc20 name 'Wrapped Ether'
expect(wethOject.storage["0x0000000000000000000000000000000000000000000000000000000000000003"]).to.equal(
"0x577261707065642045746865720000000000000000000000000000000000001a"
);

// Storage for erc20 code 'WETH'
expect(wethOject.storage["0x0000000000000000000000000000000000000000000000000000000000000004"]).to.equal(
"0x5745544800000000000000000000000000000000000000000000000000000008"
);
}
}
if (sovereignWETHAddress !== ethers.ZeroAddress) {
expect(bridgeProxy.storage["0x000000000000000000000000000000000000000000000000000000000000006f"]).to.include(
sovereignWETHAddress.toLowerCase().slice(2)
);
}
if (sovereignWETHAddressIsNotMintable) {
expect(bridgeProxy.storage["0xc7edf51165adec508a5250d96d0588939529f9442a12e2ffa25d7692caac0ef0"]).to.equal(
"0x0000000000000000000000000000000000000000000000000000000000000001"
);
}
expect(bridgeProxy.storage["0x0000000000000000000000000000000000000000000000000000000000000068"]).to.include(
gerProxy.address.toLowerCase().slice(2)

// Storage values for gasTokenMetadata, its a bytes variable
let offset = 2 + 64;
expect(bridgeProxy.storage["0x9930d9ff0dee0ef5ca2f7710ea66b8f84dd0f5f5351ecffe72b952cd9db7142a"]).to.include(
gasTokenMetadata.slice(2, offset)
);
expect(bridgeProxy.storage["0x00000000000000000000000000000000000000000000000000000000000000a3"]).to.include(
bridgeManager.toLowerCase().slice(2)
expect(bridgeProxy.storage["0x9930d9ff0dee0ef5ca2f7710ea66b8f84dd0f5f5351ecffe72b952cd9db7142b"]).to.include(
gasTokenMetadata.slice(offset, offset + 64)
);
offset += 64;
expect(bridgeProxy.storage["0x9930d9ff0dee0ef5ca2f7710ea66b8f84dd0f5f5351ecffe72b952cd9db7142c"]).to.include(
gasTokenMetadata.slice(offset, offset + 64)
);
offset += 64;
expect(bridgeProxy.storage["0x9930d9ff0dee0ef5ca2f7710ea66b8f84dd0f5f5351ecffe72b952cd9db7142d"]).to.include(
gasTokenMetadata.slice(offset, offset + 64)
);
offset += 64;
expect(bridgeProxy.storage["0x9930d9ff0dee0ef5ca2f7710ea66b8f84dd0f5f5351ecffe72b952cd9db7142e"]).to.include(
gasTokenMetadata.slice(offset, offset + 64)
);
offset += 64;
expect(bridgeProxy.storage["0x9930d9ff0dee0ef5ca2f7710ea66b8f84dd0f5f5351ecffe72b952cd9db7142f"]).to.include(
gasTokenMetadata.slice(offset, offset + 64)
);
offset += 64;
expect(bridgeProxy.storage["0x9930d9ff0dee0ef5ca2f7710ea66b8f84dd0f5f5351ecffe72b952cd9db71430"]).to.include(
gasTokenMetadata.slice(offset, offset + 64)
);

// Check bridgeAddress is included in ger bytecode
Expand All @@ -244,10 +332,22 @@ async function updateVanillaGenesis(genesis, chainID, initializeParams) {
return acc;
}, {});

// Sanity check ger storage
// CHECK GER PROXY STORAGE
// Storage value of proxy implementation
expect(gerProxy.storage["0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc"]).to.include(
oldGer.address.toLowerCase().slice(2)
);

// Storage value of proxyAdmin
expect(gerProxy.storage["0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103"]).to.include(
proxyAdminObject.address.toLowerCase().slice(2)
);

// Storage value of global exit root updater
expect(gerProxy.storage["0x0000000000000000000000000000000000000000000000000000000000000034"]).to.include(
globalExitRootUpdater.toLowerCase().slice(2)
);

// Create a new zkEVM to generate a genesis an empty system address storage
const zkEVMDB3 = await ZkEVMDB.newZkEVM(
new MemDB(F),
Expand Down

0 comments on commit d5b0cc1

Please sign in to comment.