From bef357230ee7aa6b716e53504ba7a69372c13fd6 Mon Sep 17 00:00:00 2001 From: Ignasi Date: Mon, 16 Sep 2024 10:20:27 +0200 Subject: [PATCH] Add more testing --- ...hains.sol => IBridgeL2SovereignChains.sol} | 12 +- .../BridgeL2SovereignChain.sol | 35 +- .../GlobalExitRootManagerL2SovereignChain.sol | 26 +- .../BridgeL2GasTokensSovereignChains.test.ts | 1622 +++++++++++++++++ .../BridgeL2SovereignChain.test.ts | 1028 ++++++----- 5 files changed, 2225 insertions(+), 498 deletions(-) rename contracts/v2/interfaces/{IPolygonZkEVMBridgeL2SovereignChains.sol => IBridgeL2SovereignChains.sol} (94%) create mode 100644 test/contractsv2/BridgeL2GasTokensSovereignChains.test.ts diff --git a/contracts/v2/interfaces/IPolygonZkEVMBridgeL2SovereignChains.sol b/contracts/v2/interfaces/IBridgeL2SovereignChains.sol similarity index 94% rename from contracts/v2/interfaces/IPolygonZkEVMBridgeL2SovereignChains.sol rename to contracts/v2/interfaces/IBridgeL2SovereignChains.sol index dac61b920..d419d147e 100644 --- a/contracts/v2/interfaces/IPolygonZkEVMBridgeL2SovereignChains.sol +++ b/contracts/v2/interfaces/IBridgeL2SovereignChains.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.20; import "../../interfaces/IBasePolygonZkEVMGlobalExitRoot.sol"; -interface IPolygonZkEVMBridgeL2SovereignChains { +interface IBridgeL2SovereignChains { /** * @dev Thrown when the destination network is invalid */ @@ -100,6 +100,16 @@ interface IPolygonZkEVMBridgeL2SovereignChains { */ error NotValidBridgeManager(); + /** + * @dev Thrown when try to set a zero address to a non valid zero address field + */ + error InvalidZeroAddress(); + + /** + * @dev Thrown when the origin network is invalid + */ + error OriginNetworkInvalid(); + function wrappedTokenToTokenInfo( address destinationAddress ) external view returns (uint32, address); diff --git a/contracts/v2/sovereignChains/BridgeL2SovereignChain.sol b/contracts/v2/sovereignChains/BridgeL2SovereignChain.sol index ac162d592..8cbff8620 100644 --- a/contracts/v2/sovereignChains/BridgeL2SovereignChain.sol +++ b/contracts/v2/sovereignChains/BridgeL2SovereignChain.sol @@ -8,18 +8,18 @@ import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20Metadat import "../../lib/TokenWrapped.sol"; import "../../interfaces/IBasePolygonZkEVMGlobalExitRoot.sol"; import "../../interfaces/IBridgeMessageReceiver.sol"; -import "../interfaces/IPolygonZkEVMBridgeL2SovereignChains.sol"; +import "../interfaces/IBridgeL2SovereignChains.sol"; import "../../lib/EmergencyManager.sol"; import "../../lib/GlobalExitRootLib.sol"; /** - * PolygonZkEVMBridge that will be deployed on Ethereum and all Polygon rollups + * Sovereign chains bridge that will be deployed on Ethereum and all Sovereign chains * Contract responsible to manage the token interactions with other networks */ contract BridgeL2SovereignChain is DepositContractV2, EmergencyManager, - IPolygonZkEVMBridgeL2SovereignChains + IBridgeL2SovereignChains { using SafeERC20Upgradeable for IERC20Upgradeable; @@ -150,7 +150,7 @@ contract BridgeL2SovereignChain is * @param _gasTokenAddress gas token address * @param _gasTokenNetwork gas token network * @param _globalExitRootManager global exit root manager address - * @param _polygonRollupManager polygonZkEVM address + * @param _polygonRollupManager Rollup manager address * @notice The value of `_polygonRollupManager` on the L2 deployment of the contract will be address(0), so * emergency state is not possible for the L2 deployment of the bridge, intentionally * @param _gasTokenMetadata Abi encoded gas token metadata @@ -224,10 +224,10 @@ contract BridgeL2SovereignChain is * @param permitData Raw data of the call `permit` of the token */ function bridgeAsset( - uint32 destinationNetwork, // 1 - address destinationAddress, // whatever - uint256 amount, // 1 - address token, // ETH + uint32 destinationNetwork, + address destinationAddress, + uint256 amount, + address token, bool forceUpdateGlobalExitRoot, bytes calldata permitData ) public payable virtual ifNotEmergencyState nonReentrant { @@ -235,7 +235,7 @@ contract BridgeL2SovereignChain is revert DestinationNetworkInvalid(); } - address originTokenAddress; // Address of the token at the origin network + address originTokenAddress; uint32 originNetwork; bytes memory metadata; uint256 leafAmount = amount; @@ -819,6 +819,7 @@ contract BridgeL2SovereignChain is * origin token. * @notice If this function is called multiple times for the same existingTokenAddress, * this will override the previous calls and only keep the last sovereignTokenAddress. + * @notice The tokenInfoToWrappedToken mapping value is replaced by the new sovereign address but it's not the case for the wrappedTokenToTokenInfo map where the value is added, this way user will always be able to withdraw their tokens * @param originNetwork Origin network * @param originTokenAddress Origin token address, 0 address is reserved for ether * @param sovereignTokenAddress Address of the sovereign wrapped token @@ -830,15 +831,21 @@ contract BridgeL2SovereignChain is address sovereignTokenAddress, bool isNotMintable ) external onlyBridgeManager { - // TODO: Add checks - // - origin and sovereign token address are not 0 - // - originnetwork != current network, wrapped always other networks - // Handle claimAsset on target chain + // origin and sovereign token address are not 0 + if(originTokenAddress == address(0) || sovereignTokenAddress == address(0)) { + revert InvalidZeroAddress(); + } + // originnetwork != current network, wrapped tokens are always from other networks + if (originNetwork == networkID) { + revert OriginNetworkInvalid(); + } + // Compute token info hash bytes32 tokenInfoHash = keccak256( abi.encodePacked(originNetwork, originTokenAddress) ); + // Set the address of the wrapper tokenInfoToWrappedToken[tokenInfoHash] = sovereignTokenAddress; - // todo: comment: you will always can withdraw (explain) + // Set the token info mapping wrappedTokenToTokenInfo[sovereignTokenAddress] = TokenInformation( originNetwork, originTokenAddress diff --git a/contracts/v2/sovereignChains/GlobalExitRootManagerL2SovereignChain.sol b/contracts/v2/sovereignChains/GlobalExitRootManagerL2SovereignChain.sol index 43e8728d8..f798c75cc 100644 --- a/contracts/v2/sovereignChains/GlobalExitRootManagerL2SovereignChain.sol +++ b/contracts/v2/sovereignChains/GlobalExitRootManagerL2SovereignChain.sol @@ -14,21 +14,19 @@ contract GlobalExitRootManagerL2SovereignChain is // Store every global exit root: Root --> timestamp mapping(bytes32 => uint256) public globalExitRootMap; - // Rollup exit root will be updated for every PolygonZkEVMBridge call + // Rollup exit root will be updated for every Sovereign chain call bytes32 public lastRollupExitRoot; - // PolygonZkEVM Bridge address + // Sovereign chain Bridge address address public immutable bridgeAddress; /** * @dev Emitted when a new global exit root is inserted */ - event InsertGlobalExitRoot( - bytes32 indexed newGlobalExitRoot - ); + event InsertGlobalExitRoot(bytes32 indexed newGlobalExitRoot); /** - * @param _bridgeAddress PolygonZkEVMBridge contract address + * @param _bridgeAddress BridgeL2SovereignChain contract address */ constructor(address _bridgeAddress) { bridgeAddress = _bridgeAddress; @@ -45,11 +43,21 @@ contract GlobalExitRootManagerL2SovereignChain is _; } + /** + * @notice Only allows a function to be callable by the bride contract + */ + modifier onlyBridgeAddress() { + if (msg.sender != bridgeAddress) { + revert OnlyAllowedContracts(); + } + _; + } + /** * @notice Update the exit root of one of the networks and the global exit root * @param newRoot new exit tree root */ - function updateExitRoot(bytes32 newRoot) external onlyTrustedSequencer { + function updateExitRoot(bytes32 newRoot) external onlyBridgeAddress() { lastRollupExitRoot = newRoot; } @@ -59,9 +67,7 @@ contract GlobalExitRootManagerL2SovereignChain is // do not update timestamp if already set if (globalExitRootMap[_newRoot] == 0) { globalExitRootMap[_newRoot] = block.timestamp; - emit InsertGlobalExitRoot( - _newRoot - ); + emit InsertGlobalExitRoot(_newRoot); } } } diff --git a/test/contractsv2/BridgeL2GasTokensSovereignChains.test.ts b/test/contractsv2/BridgeL2GasTokensSovereignChains.test.ts new file mode 100644 index 000000000..b14acb307 --- /dev/null +++ b/test/contractsv2/BridgeL2GasTokensSovereignChains.test.ts @@ -0,0 +1,1622 @@ +import {expect} from "chai"; +import {ethers, upgrades} from "hardhat"; +import { + VerifierRollupHelperMock, + ERC20PermitMock, + PolygonRollupManagerMock, + PolygonZkEVMGlobalExitRoot, + PolygonZkEVMBridgeV2, + PolygonZkEVMV2, + PolygonRollupBase, + TokenWrapped, +} from "../../typechain-types"; +import {takeSnapshot, time} from "@nomicfoundation/hardhat-network-helpers"; +import {processorUtils, contractUtils, MTBridge, mtBridgeUtils} from "@0xpolygonhermez/zkevm-commonjs"; +const {calculateSnarkInput, calculateAccInputHash, calculateBatchHashData} = contractUtils; +const MerkleTreeBridge = MTBridge; +const {verifyMerkleProof, getLeafValue} = mtBridgeUtils; +import {setBalance} from "@nomicfoundation/hardhat-network-helpers"; + +function calculateGlobalExitRoot(mainnetExitRoot: any, rollupExitRoot: any) { + return ethers.solidityPackedKeccak256(["bytes32", "bytes32"], [mainnetExitRoot, rollupExitRoot]); +} +const _GLOBAL_INDEX_MAINNET_FLAG = 2n ** 64n; + +function computeGlobalIndex(indexLocal: any, indexRollup: any, isMainnet: Boolean) { + if (isMainnet === true) { + return BigInt(indexLocal) + _GLOBAL_INDEX_MAINNET_FLAG; + } else { + return BigInt(indexLocal) + BigInt(indexRollup) * 2n ** 32n; + } +} + +describe("PolygonZkEVMBridge Gas tokens tests", () => { + upgrades.silenceWarnings(); + + let polygonZkEVMBridgeContract: PolygonZkEVMBridgeV2; + let polTokenContract: ERC20PermitMock; + let polygonZkEVMGlobalExitRoot: PolygonZkEVMGlobalExitRoot; + + let deployer: any; + let rollupManager: any; + let acc1: any; + + const tokenName = "Matic Token"; + const tokenSymbol = "MATIC"; + const decimals = 18; + const tokenInitialBalance = ethers.parseEther("20000000"); + const metadataToken = ethers.AbiCoder.defaultAbiCoder().encode( + ["string", "string", "uint8"], + [tokenName, tokenSymbol, decimals] + ); + const networkIDMainnet = 0; + const networkIDRollup = 1; + + const LEAF_TYPE_ASSET = 0; + const LEAF_TYPE_MESSAGE = 1; + + const polygonZkEVMAddress = ethers.ZeroAddress; + + let gasTokenAddress: any; + let gasTokenNetwork: any; + let gasTokenMetadata: any; + let WETHToken: TokenWrapped; + + beforeEach("Deploy contracts", async () => { + // load signers + [deployer, rollupManager, acc1] = await ethers.getSigners(); + + // deploy PolygonZkEVMBridge + const polygonZkEVMBridgeFactory = await ethers.getContractFactory("PolygonZkEVMBridgeV2"); + polygonZkEVMBridgeContract = (await upgrades.deployProxy(polygonZkEVMBridgeFactory, [], { + initializer: false, + unsafeAllow: ["constructor"], + })) as unknown as PolygonZkEVMBridgeV2; + + // deploy global exit root manager + const PolygonZkEVMGlobalExitRootFactory = await ethers.getContractFactory("PolygonZkEVMGlobalExitRoot"); + polygonZkEVMGlobalExitRoot = await PolygonZkEVMGlobalExitRootFactory.deploy( + rollupManager.address, + polygonZkEVMBridgeContract.target + ); + + // deploy token + const maticTokenFactory = await ethers.getContractFactory("ERC20PermitMock"); + polTokenContract = await maticTokenFactory.deploy( + tokenName, + tokenSymbol, + deployer.address, + tokenInitialBalance + ); + + gasTokenAddress = polTokenContract.target; + gasTokenNetwork = 0; + gasTokenMetadata = metadataToken; + + await polygonZkEVMBridgeContract.initialize( + networkIDMainnet, + polTokenContract.target, // zero for ether + 0, // zero for ether + polygonZkEVMGlobalExitRoot.target, + rollupManager.address, + metadataToken + ); + + // calculate the weth address: + const tokenWrappedFactory = await ethers.getContractFactory("TokenWrapped"); + // create2 parameters + const minimalBytecodeProxy = await polygonZkEVMBridgeContract.BASE_INIT_BYTECODE_WRAPPED_TOKEN(); + const WETHName = "Wrapped Ether"; + const WETHSymbol = "WETH"; + const WETHDecimals = 18; + const metadataWETH = ethers.AbiCoder.defaultAbiCoder().encode( + ["string", "string", "uint8"], + [WETHName, WETHSymbol, WETHDecimals] + ); + + const hashInitCode = ethers.solidityPackedKeccak256(["bytes", "bytes"], [minimalBytecodeProxy, metadataWETH]); + const precalculatedWeth = await ethers.getCreate2Address( + polygonZkEVMBridgeContract.target as string, + ethers.ZeroHash, // zero only for weth + hashInitCode + ); + WETHToken = tokenWrappedFactory.attach(precalculatedWeth) as TokenWrapped; + + expect(await polygonZkEVMBridgeContract.WETHToken()).to.be.equal(WETHToken.target); + }); + + it("should check the constructor parameters", async () => { + expect(await polygonZkEVMBridgeContract.globalExitRootManager()).to.be.equal(polygonZkEVMGlobalExitRoot.target); + expect(await polygonZkEVMBridgeContract.networkID()).to.be.equal(networkIDMainnet); + expect(await polygonZkEVMBridgeContract.polygonRollupManager()).to.be.equal(rollupManager.address); + + expect(await polygonZkEVMBridgeContract.gasTokenAddress()).to.be.equal(gasTokenAddress); + expect(await polygonZkEVMBridgeContract.gasTokenNetwork()).to.be.equal(gasTokenNetwork); + expect(await polygonZkEVMBridgeContract.gasTokenMetadata()).to.be.equal(gasTokenMetadata); + }); + + it("should check the initalized function", async () => { + // deploy PolygonZkEVMBridge + const polygonZkEVMBridgeFactory = await ethers.getContractFactory("PolygonZkEVMBridgeV2"); + const bridge = await upgrades.deployProxy(polygonZkEVMBridgeFactory, [], { + initializer: false, + unsafeAllow: ["constructor"], + }); + + await expect( + bridge.initialize( + networkIDMainnet, + ethers.ZeroAddress, // zero for ether + 1, // zero for ether + polygonZkEVMGlobalExitRoot.target, + rollupManager.address, + "0x" + ) + ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "GasTokenNetworkMustBeZeroOnEther"); + }); + + it("should check the emergency state", async () => { + expect(await polygonZkEVMBridgeContract.isEmergencyState()).to.be.equal(false); + + await expect(polygonZkEVMBridgeContract.activateEmergencyState()).to.be.revertedWithCustomError( + polygonZkEVMBridgeContract, + "OnlyRollupManager" + ); + await expect(polygonZkEVMBridgeContract.connect(rollupManager).activateEmergencyState()).to.emit( + polygonZkEVMBridgeContract, + "EmergencyStateActivated" + ); + + expect(await polygonZkEVMBridgeContract.isEmergencyState()).to.be.equal(true); + + await expect( + polygonZkEVMBridgeContract.connect(deployer).deactivateEmergencyState() + ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "OnlyRollupManager"); + + await expect(polygonZkEVMBridgeContract.connect(rollupManager).deactivateEmergencyState()).to.emit( + polygonZkEVMBridgeContract, + "EmergencyStateDeactivated" + ); + + expect(await polygonZkEVMBridgeContract.isEmergencyState()).to.be.equal(false); + }); + + it("should PolygonZkEVM bridge asset and verify merkle proof", async () => { + const depositCount = await polygonZkEVMBridgeContract.depositCount(); + const originNetwork = networkIDMainnet; + const tokenAddress = polTokenContract.target; + const amount = ethers.parseEther("10"); + const destinationNetwork = networkIDRollup; + const destinationAddress = deployer.address; + + const metadata = metadataToken; + const metadataHash = ethers.solidityPackedKeccak256(["bytes"], [metadata]); + + const balanceDeployer = await polTokenContract.balanceOf(deployer.address); + const balanceBridge = await polTokenContract.balanceOf(polygonZkEVMBridgeContract.target); + + const rollupExitRoot = await polygonZkEVMGlobalExitRoot.lastRollupExitRoot(); + + // create a new deposit + await expect(polTokenContract.approve(polygonZkEVMBridgeContract.target, amount)) + .to.emit(polTokenContract, "Approval") + .withArgs(deployer.address, polygonZkEVMBridgeContract.target, amount); + + // pre compute root merkle tree in Js + const height = 32; + const merkleTree = new MerkleTreeBridge(height); + const leafValue = getLeafValue( + LEAF_TYPE_ASSET, + originNetwork, + tokenAddress, + destinationNetwork, + destinationAddress, + amount, + metadataHash + ); + merkleTree.add(leafValue); + const rootJSMainnet = merkleTree.getRoot(); + + await expect( + polygonZkEVMBridgeContract.bridgeAsset( + destinationNetwork, + destinationAddress, + amount, + tokenAddress, + true, + "0x", + {value: 1} + ) + ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "MsgValueNotZero"); + + await expect( + polygonZkEVMBridgeContract.bridgeAsset( + destinationNetwork, + destinationAddress, + amount, + tokenAddress, + true, + "0x" + ) + ) + .to.emit(polygonZkEVMBridgeContract, "BridgeEvent") + .withArgs( + LEAF_TYPE_ASSET, + originNetwork, + tokenAddress, + destinationNetwork, + destinationAddress, + amount, + metadata, + depositCount + ) + .to.emit(polygonZkEVMGlobalExitRoot, "UpdateGlobalExitRoot") + .withArgs(rootJSMainnet, rollupExitRoot); + + expect(await polTokenContract.balanceOf(deployer.address)).to.be.equal(balanceDeployer - amount); + expect(await polTokenContract.balanceOf(polygonZkEVMBridgeContract.target)).to.be.equal(balanceBridge + amount); + expect(await polygonZkEVMBridgeContract.lastUpdatedDepositCount()).to.be.equal(1); + + // check merkle root with SC + const rootSCMainnet = await polygonZkEVMBridgeContract.getRoot(); + expect(rootSCMainnet).to.be.equal(rootJSMainnet); + + // check merkle proof + const proof = merkleTree.getProofTreeByIndex(0); + const index = 0; + + // verify merkle proof + expect(verifyMerkleProof(leafValue, proof, index, rootSCMainnet)).to.be.equal(true); + expect(await polygonZkEVMBridgeContract.verifyMerkleProof(leafValue, proof, index, rootSCMainnet)).to.be.equal( + true + ); + + const computedGlobalExitRoot = calculateGlobalExitRoot(rootJSMainnet, rollupExitRoot); + expect(computedGlobalExitRoot).to.be.equal(await polygonZkEVMGlobalExitRoot.getLastGlobalExitRoot()); + }); + + it("should PolygonZkEVMBridge message and verify merkle proof", async () => { + const depositCount = await polygonZkEVMBridgeContract.depositCount(); + const originNetwork = networkIDMainnet; + const originAddress = deployer.address; + const amount = ethers.parseEther("10"); + const destinationNetwork = networkIDRollup; + const destinationAddress = deployer.address; + + const metadata = metadataToken; + const metadataHash = ethers.solidityPackedKeccak256(["bytes"], [metadata]); + const rollupExitRoot = await polygonZkEVMGlobalExitRoot.lastRollupExitRoot(); + + // pre compute root merkle tree in Js + const height = 32; + const merkleTree = new MerkleTreeBridge(height); + const leafValue = getLeafValue( + LEAF_TYPE_MESSAGE, + originNetwork, + originAddress, + destinationNetwork, + destinationAddress, + amount, + metadataHash + ); + merkleTree.add(leafValue); + const rootJSMainnet = merkleTree.getRoot(); + + // using gas TOkens cannot use bridge message with etther + await expect( + polygonZkEVMBridgeContract.bridgeMessage(destinationNetwork, destinationAddress, true, metadata, { + value: amount, + }) + ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "NoValueInMessagesOnGasTokenNetworks"); + + // Use bridgeMessageWETH instead! + + // cannot use value + await expect( + polygonZkEVMBridgeContract.bridgeMessageWETH( + destinationNetwork, + destinationAddress, + amount, + true, + metadata, + { + value: amount, + } + ) + ).to.be.reverted; + + // Use bridgeMessageWETH instead! + await expect( + polygonZkEVMBridgeContract.bridgeMessageWETH(destinationNetwork, destinationAddress, amount, true, metadata) + ).to.be.revertedWith("ERC20: burn amount exceeds balance"); + + // Mock mint weth + await ethers.provider.send("hardhat_impersonateAccount", [polygonZkEVMBridgeContract.target]); + const bridgeMock = await ethers.getSigner(polygonZkEVMBridgeContract.target as any); + + await WETHToken.connect(bridgeMock).mint(deployer.address, amount, {gasPrice: 0}); + + await expect( + polygonZkEVMBridgeContract.bridgeMessageWETH(destinationNetwork, destinationAddress, amount, true, metadata) + ) + .to.emit(polygonZkEVMBridgeContract, "BridgeEvent") + .withArgs( + LEAF_TYPE_MESSAGE, + originNetwork, + originAddress, + destinationNetwork, + destinationAddress, + amount, + metadata, + depositCount + ); + + // check merkle root with SC + const rootSCMainnet = await polygonZkEVMBridgeContract.getRoot(); + expect(rootSCMainnet).to.be.equal(rootJSMainnet); + + // check merkle proof + const proof = merkleTree.getProofTreeByIndex(0); + const index = 0; + + // verify merkle proof + expect(verifyMerkleProof(leafValue, proof, index, rootSCMainnet)).to.be.equal(true); + expect(await polygonZkEVMBridgeContract.verifyMerkleProof(leafValue, proof, index, rootSCMainnet)).to.be.equal( + true + ); + + const computedGlobalExitRoot = calculateGlobalExitRoot(rootJSMainnet, rollupExitRoot); + expect(computedGlobalExitRoot).to.be.equal(await polygonZkEVMGlobalExitRoot.getLastGlobalExitRoot()); + + // bridge message without value is fine + await expect( + polygonZkEVMBridgeContract.bridgeMessage(destinationNetwork, destinationAddress, true, metadata, {}) + ) + .to.emit(polygonZkEVMBridgeContract, "BridgeEvent") + .withArgs( + LEAF_TYPE_MESSAGE, + originNetwork, + originAddress, + destinationNetwork, + destinationAddress, + 0, + metadata, + depositCount + 1n + ); + }); + + it("should PolygonZkEVM bridge asset and message to check global exit root updates", async () => { + const depositCount = await polygonZkEVMBridgeContract.depositCount(); + const originNetwork = networkIDMainnet; + const tokenAddress = polTokenContract.target; + const amount = ethers.parseEther("10"); + const destinationNetwork = networkIDRollup; + const destinationAddress = deployer.address; + + const metadata = metadataToken; + const metadataHash = ethers.solidityPackedKeccak256(["bytes"], [metadata]); + + const balanceDeployer = await polTokenContract.balanceOf(deployer.address); + const balanceBridge = await polTokenContract.balanceOf(polygonZkEVMBridgeContract.target); + + const rollupExitRoot = await polygonZkEVMGlobalExitRoot.lastRollupExitRoot(); + + // create a new deposit + await expect(polTokenContract.approve(polygonZkEVMBridgeContract.target, amount)) + .to.emit(polTokenContract, "Approval") + .withArgs(deployer.address, polygonZkEVMBridgeContract.target, amount); + + // pre compute root merkle tree in Js + const height = 32; + const merkleTree = new MerkleTreeBridge(height); + const leafValue = getLeafValue( + LEAF_TYPE_ASSET, + originNetwork, + tokenAddress, + destinationNetwork, + destinationAddress, + amount, + metadataHash + ); + merkleTree.add(leafValue); + const rootJSMainnet = merkleTree.getRoot(); + + await expect( + polygonZkEVMBridgeContract.bridgeAsset( + destinationNetwork, + destinationAddress, + amount, + tokenAddress, + false, + "0x" + ) + ) + .to.emit(polygonZkEVMBridgeContract, "BridgeEvent") + .withArgs( + LEAF_TYPE_ASSET, + originNetwork, + tokenAddress, + destinationNetwork, + destinationAddress, + amount, + metadata, + depositCount + ); + + expect(await polTokenContract.balanceOf(deployer.address)).to.be.equal(balanceDeployer - amount); + expect(await polTokenContract.balanceOf(polygonZkEVMBridgeContract.target)).to.be.equal(balanceBridge + amount); + expect(await polygonZkEVMBridgeContract.lastUpdatedDepositCount()).to.be.equal(0); + expect(await polygonZkEVMGlobalExitRoot.lastMainnetExitRoot()).to.be.equal(ethers.ZeroHash); + + // check merkle root with SC + const rootSCMainnet = await polygonZkEVMBridgeContract.getRoot(); + expect(rootSCMainnet).to.be.equal(rootJSMainnet); + + // Update global exit root + await expect(polygonZkEVMBridgeContract.updateGlobalExitRoot()) + .to.emit(polygonZkEVMGlobalExitRoot, "UpdateGlobalExitRoot") + .withArgs(rootJSMainnet, rollupExitRoot); + + // no state changes since there are not any deposit pending to be updated + await polygonZkEVMBridgeContract.updateGlobalExitRoot(); + expect(await polygonZkEVMBridgeContract.lastUpdatedDepositCount()).to.be.equal(1); + expect(await polygonZkEVMGlobalExitRoot.lastMainnetExitRoot()).to.be.equal(rootJSMainnet); + + const computedGlobalExitRoot = calculateGlobalExitRoot(rootJSMainnet, rollupExitRoot); + expect(computedGlobalExitRoot).to.be.equal(await polygonZkEVMGlobalExitRoot.getLastGlobalExitRoot()); + + // bridge message + await expect( + polygonZkEVMBridgeContract.bridgeMessage(destinationNetwork, destinationAddress, false, metadata, { + value: amount, + }) + ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "NoValueInMessagesOnGasTokenNetworks"); + + // Mock mint weth + await ethers.provider.send("hardhat_impersonateAccount", [polygonZkEVMBridgeContract.target]); + const bridgeMock = await ethers.getSigner(polygonZkEVMBridgeContract.target as any); + await WETHToken.connect(bridgeMock).mint(deployer.address, amount, {gasPrice: 0}); + + await expect( + polygonZkEVMBridgeContract.bridgeMessageWETH( + destinationNetwork, + destinationAddress, + amount, + false, + metadata + ) + ) + .to.emit(polygonZkEVMBridgeContract, "BridgeEvent") + .withArgs( + LEAF_TYPE_MESSAGE, + originNetwork, + deployer.address, + destinationNetwork, + destinationAddress, + amount, + metadata, + 1 + ); + expect(await polygonZkEVMBridgeContract.lastUpdatedDepositCount()).to.be.equal(1); + expect(await polygonZkEVMGlobalExitRoot.lastMainnetExitRoot()).to.be.equal(rootJSMainnet); + + // Update global exit root + await expect(polygonZkEVMBridgeContract.updateGlobalExitRoot()).to.emit( + polygonZkEVMGlobalExitRoot, + "UpdateGlobalExitRoot" + ); + + expect(await polygonZkEVMBridgeContract.lastUpdatedDepositCount()).to.be.equal(2); + expect(await polygonZkEVMGlobalExitRoot.lastMainnetExitRoot()).to.not.be.equal(rootJSMainnet); + + // Just to have the metric of a low cost bridge Asset + const tokenAddress2 = WETHToken.target; // Ether + const amount2 = ethers.parseEther("10"); + await WETHToken.connect(bridgeMock).mint(deployer.address, amount2, {gasPrice: 0}); + + await expect( + polygonZkEVMBridgeContract.bridgeAsset( + destinationNetwork, + destinationAddress, + amount2, + tokenAddress2, + false, + "0x" + ) + ) + .to.emit(polygonZkEVMBridgeContract, "BridgeEvent") + .withArgs( + LEAF_TYPE_ASSET, + originNetwork, + ethers.ZeroAddress, + destinationNetwork, + destinationAddress, + amount2, + "0x", + 2 + ) + .to.emit(WETHToken, "Transfer") + .withArgs(deployer.address, ethers.ZeroAddress, amount2); + }); + + it("should claim Gas tokens from Mainnet to Mainnet", async () => { + const originNetwork = networkIDMainnet; + const tokenAddress = polTokenContract.target; + const amount = ethers.parseEther("10"); + const destinationNetwork = networkIDMainnet; + const destinationAddress = acc1.address; + + const metadata = metadataToken; + const metadataHash = ethers.solidityPackedKeccak256(["bytes"], [metadata]); + + const rollupExitRoot = await polygonZkEVMGlobalExitRoot.lastRollupExitRoot(); + + // compute root merkle tree in Js + const height = 32; + const merkleTreeLocal = new MerkleTreeBridge(height); + const leafValue = getLeafValue( + LEAF_TYPE_ASSET, + originNetwork, + tokenAddress, + destinationNetwork, + destinationAddress, + amount, + metadataHash + ); + merkleTreeLocal.add(leafValue); + + const mainnetExitRoot = merkleTreeLocal.getRoot(); + const indexRollup = 0; + + // check only rollup account with update rollup exit root + await expect(polygonZkEVMGlobalExitRoot.updateExitRoot(mainnetExitRoot)).to.be.revertedWithCustomError( + polygonZkEVMGlobalExitRoot, + "OnlyAllowedContracts" + ); + + // add rollup Merkle root + await ethers.provider.send("hardhat_impersonateAccount", [polygonZkEVMBridgeContract.target]); + const bridgemoCK = await ethers.getSigner(polygonZkEVMBridgeContract.target as any); + + // await deployer.sendTransaction({ + // to: bridgemoCK.address, + // value: ethers.parseEther("1"), + // }); + + await expect(polygonZkEVMGlobalExitRoot.connect(bridgemoCK).updateExitRoot(mainnetExitRoot, {gasPrice: 0})) + .to.emit(polygonZkEVMGlobalExitRoot, "UpdateGlobalExitRoot") + .withArgs(mainnetExitRoot, rollupExitRoot); + + // check roots + const rollupExitRootSC = await polygonZkEVMGlobalExitRoot.lastRollupExitRoot(); + expect(rollupExitRootSC).to.be.equal(rollupExitRoot); + const mainnetExitRootSC = await polygonZkEVMGlobalExitRoot.lastMainnetExitRoot(); + expect(mainnetExitRootSC).to.be.equal(mainnetExitRoot); + + const computedGlobalExitRoot = calculateGlobalExitRoot(mainnetExitRoot, rollupExitRootSC); + expect(computedGlobalExitRoot).to.be.equal(await polygonZkEVMGlobalExitRoot.getLastGlobalExitRoot()); + + // check merkle proof + + // Merkle proof local + const indexLocal = 0; + const proofLocal = merkleTreeLocal.getProofTreeByIndex(indexLocal); + + // verify merkle proof + expect(verifyMerkleProof(leafValue, proofLocal, indexLocal, mainnetExitRoot)).to.be.equal(true); + + const globalIndex = computeGlobalIndex(indexLocal, indexRollup, true); + + /* + * claim + * Can't claim without native (ether) + */ + await expect( + polygonZkEVMBridgeContract.claimAsset( + proofLocal, + proofLocal, + globalIndex, + mainnetExitRoot, + rollupExitRootSC, + originNetwork, + tokenAddress, + destinationNetwork, + destinationAddress, + amount, + metadata + ) + ).to.be.reverted; + + await setBalance(polygonZkEVMBridgeContract.target as any, amount); + + expect(false).to.be.equal(await polygonZkEVMBridgeContract.isClaimed(indexLocal, indexRollup + 1)); + + const initialBalance = await ethers.provider.getBalance(polygonZkEVMBridgeContract.target); + + await expect( + polygonZkEVMBridgeContract.claimAsset( + proofLocal, + proofLocal, + globalIndex, + mainnetExitRoot, + rollupExitRootSC, + originNetwork, + tokenAddress, + destinationNetwork, + destinationAddress, + amount, + metadata, + { + gasPrice: 0, + } + ) + ) + .to.emit(polygonZkEVMBridgeContract, "ClaimEvent") + .withArgs(globalIndex, originNetwork, tokenAddress, destinationAddress, amount); + + // Can't claim because nullifier + await expect( + polygonZkEVMBridgeContract.claimAsset( + proofLocal, + proofLocal, + globalIndex, + mainnetExitRoot, + rollupExitRootSC, + originNetwork, + tokenAddress, + destinationNetwork, + destinationAddress, + amount, + metadata + ) + ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "AlreadyClaimed"); + expect(true).to.be.equal(await polygonZkEVMBridgeContract.isClaimed(indexLocal, indexRollup + 1)); + + expect(initialBalance - amount).to.be.equal( + await ethers.provider.getBalance(polygonZkEVMBridgeContract.target) + ); + }); + + it("should claim tokens Gas tokens from Mainnet to Mainnet", async () => { + const originNetwork = networkIDMainnet; + const tokenAddress = polTokenContract.target; + const amount = ethers.parseEther("10"); + const destinationNetwork = networkIDMainnet; + const destinationAddress = acc1.address; + + const metadata = metadataToken; + const metadataHash = ethers.solidityPackedKeccak256(["bytes"], [metadata]); + + const mainnetExitRoot = await polygonZkEVMGlobalExitRoot.lastMainnetExitRoot(); + + // compute root merkle tree in Js + const height = 32; + const merkleTreeLocal = new MerkleTreeBridge(height); + const leafValue = getLeafValue( + LEAF_TYPE_ASSET, + originNetwork, + tokenAddress, + destinationNetwork, + destinationAddress, + amount, + metadataHash + ); + merkleTreeLocal.add(leafValue); + + const rootLocalRollup = merkleTreeLocal.getRoot(); + const indexRollup = 5; + + // Try claim with 10 rollup leafs + const merkleTreeRollup = new MerkleTreeBridge(height); + for (let i = 0; i < 10; i++) { + if (i == indexRollup) { + merkleTreeRollup.add(rootLocalRollup); + } else { + merkleTreeRollup.add(ethers.toBeHex(ethers.toQuantity(ethers.randomBytes(32)), 32)); + } + } + + const rootRollup = merkleTreeRollup.getRoot(); + + // check only rollup account with update rollup exit root + await expect(polygonZkEVMGlobalExitRoot.updateExitRoot(rootRollup)).to.be.revertedWithCustomError( + polygonZkEVMGlobalExitRoot, + "OnlyAllowedContracts" + ); + + // add rollup Merkle root + await expect(polygonZkEVMGlobalExitRoot.connect(rollupManager).updateExitRoot(rootRollup)) + .to.emit(polygonZkEVMGlobalExitRoot, "UpdateGlobalExitRoot") + .withArgs(mainnetExitRoot, rootRollup); + + // check roots + const rollupExitRootSC = await polygonZkEVMGlobalExitRoot.lastRollupExitRoot(); + expect(rollupExitRootSC).to.be.equal(rootRollup); + + const computedGlobalExitRoot = calculateGlobalExitRoot(mainnetExitRoot, rollupExitRootSC); + expect(computedGlobalExitRoot).to.be.equal(await polygonZkEVMGlobalExitRoot.getLastGlobalExitRoot()); + + // check merkle proof + + // Merkle proof local + const indexLocal = 0; + const proofLocal = merkleTreeLocal.getProofTreeByIndex(indexLocal); + + // Merkle proof local + const proofRollup = merkleTreeRollup.getProofTreeByIndex(indexRollup); + + // verify merkle proof + expect(verifyMerkleProof(rootLocalRollup, proofRollup, indexRollup, rootRollup)).to.be.equal(true); + expect( + await polygonZkEVMBridgeContract.verifyMerkleProof(rootLocalRollup, proofRollup, indexRollup, rootRollup) + ).to.be.equal(true); + const globalIndex = computeGlobalIndex(indexLocal, indexRollup, false); + /* + * claim + * Can't claim without tokens + */ + await expect( + polygonZkEVMBridgeContract.claimAsset( + proofLocal, + proofRollup, + Number(globalIndex), + mainnetExitRoot, + rollupExitRootSC, + originNetwork, + tokenAddress, + destinationNetwork, + destinationAddress, + amount, + metadata + ) + ).to.be.reverted; + + await setBalance(polygonZkEVMBridgeContract.target as any, amount); + + expect(false).to.be.equal(await polygonZkEVMBridgeContract.isClaimed(indexLocal, indexRollup + 1)); + + await expect( + polygonZkEVMBridgeContract.claimAsset( + proofLocal, + proofRollup, + globalIndex, + mainnetExitRoot, + rollupExitRootSC, + originNetwork, + tokenAddress, + destinationNetwork, + destinationAddress, + amount, + metadata + ) + ) + .to.emit(polygonZkEVMBridgeContract, "ClaimEvent") + .withArgs(globalIndex, originNetwork, tokenAddress, destinationAddress, amount); + + // Can't claim because nullifier + await expect( + polygonZkEVMBridgeContract.claimAsset( + proofLocal, + proofRollup, + globalIndex, + mainnetExitRoot, + rollupExitRootSC, + originNetwork, + tokenAddress, + destinationNetwork, + destinationAddress, + amount, + metadata + ) + ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "AlreadyClaimed"); + expect(true).to.be.equal(await polygonZkEVMBridgeContract.isClaimed(indexLocal, indexRollup + 1)); + }); + + it("should claim tokens from Rollup to Mainnet", async () => { + const originNetwork = networkIDRollup; + const tokenAddress = polTokenContract.target; + const amount = ethers.parseEther("10"); + const destinationNetwork = networkIDMainnet; + const destinationAddress = deployer.address; + + const metadata = metadataToken; + const metadataHash = ethers.solidityPackedKeccak256(["bytes"], [metadata]); + + const mainnetExitRoot = await polygonZkEVMGlobalExitRoot.lastMainnetExitRoot(); + + // compute root merkle tree in Js + const height = 32; + const merkleTreeLocal = new MerkleTreeBridge(height); + const leafValue = getLeafValue( + LEAF_TYPE_ASSET, + originNetwork, + tokenAddress, + destinationNetwork, + destinationAddress, + amount, + metadataHash + ); + merkleTreeLocal.add(leafValue); + merkleTreeLocal.add(leafValue); + + const rootLocalRollup = merkleTreeLocal.getRoot(); + + // Try claim with 10 rollup leafs + const merkleTreeRollup = new MerkleTreeBridge(height); + for (let i = 0; i < 10; i++) { + merkleTreeRollup.add(rootLocalRollup); + } + + const rootRollup = merkleTreeRollup.getRoot(); + + // check only rollup account with update rollup exit root + await expect(polygonZkEVMGlobalExitRoot.updateExitRoot(rootRollup)).to.be.revertedWithCustomError( + polygonZkEVMGlobalExitRoot, + "OnlyAllowedContracts" + ); + + // add rollup Merkle root + await expect(polygonZkEVMGlobalExitRoot.connect(rollupManager).updateExitRoot(rootRollup)) + .to.emit(polygonZkEVMGlobalExitRoot, "UpdateGlobalExitRoot") + .withArgs(mainnetExitRoot, rootRollup); + + // check roots + const rollupExitRootSC = await polygonZkEVMGlobalExitRoot.lastRollupExitRoot(); + expect(rollupExitRootSC).to.be.equal(rootRollup); + + const computedGlobalExitRoot = calculateGlobalExitRoot(mainnetExitRoot, rollupExitRootSC); + expect(computedGlobalExitRoot).to.be.equal(await polygonZkEVMGlobalExitRoot.getLastGlobalExitRoot()); + + // check merkle proof + + // Merkle proof local + const indexLocal = 0; + const proofLocal = merkleTreeLocal.getProofTreeByIndex(indexLocal); + + // Merkle proof local + const indexRollup = 5; + const proofRollup = merkleTreeRollup.getProofTreeByIndex(indexRollup); + + // verify merkle proof + expect(verifyMerkleProof(leafValue, proofLocal, indexLocal, rootLocalRollup)).to.be.equal(true); + expect(verifyMerkleProof(rootLocalRollup, proofRollup, indexRollup, rootRollup)).to.be.equal(true); + expect( + await polygonZkEVMBridgeContract.verifyMerkleProof(rootLocalRollup, proofRollup, indexRollup, rootRollup) + ).to.be.equal(true); + const globalIndex = computeGlobalIndex(indexLocal, indexRollup, false); + + expect(false).to.be.equal(await polygonZkEVMBridgeContract.isClaimed(indexLocal, indexRollup + 1)); + + // claim + const tokenWrappedFactory = await ethers.getContractFactory("TokenWrapped"); + // create2 parameters + const salt = ethers.solidityPackedKeccak256(["uint32", "address"], [networkIDRollup, tokenAddress]); + const minimalBytecodeProxy = await polygonZkEVMBridgeContract.BASE_INIT_BYTECODE_WRAPPED_TOKEN(); + const hashInitCode = ethers.solidityPackedKeccak256(["bytes", "bytes"], [minimalBytecodeProxy, metadataToken]); + const precalculateWrappedErc20 = await ethers.getCreate2Address( + polygonZkEVMBridgeContract.target as string, + salt, + hashInitCode + ); + const newWrappedToken = tokenWrappedFactory.attach(precalculateWrappedErc20) as TokenWrapped; + + // Use precalculatedWrapperAddress and check if matches + expect( + await polygonZkEVMBridgeContract.precalculatedWrapperAddress( + networkIDRollup, + tokenAddress, + tokenName, + tokenSymbol, + decimals + ) + ).to.be.equal(precalculateWrappedErc20); + + await expect( + polygonZkEVMBridgeContract.claimAsset( + proofLocal, + proofRollup, + globalIndex, + mainnetExitRoot, + rollupExitRootSC, + originNetwork, + tokenAddress, + destinationNetwork, + destinationAddress, + amount, + metadata + ) + ) + .to.emit(polygonZkEVMBridgeContract, "ClaimEvent") + .withArgs(globalIndex, originNetwork, tokenAddress, destinationAddress, amount) + .to.emit(polygonZkEVMBridgeContract, "NewWrappedToken") + .withArgs(originNetwork, tokenAddress, precalculateWrappedErc20, metadata) + .to.emit(newWrappedToken, "Transfer") + .withArgs(ethers.ZeroAddress, destinationAddress, amount); + + const newTokenInfo = await polygonZkEVMBridgeContract.wrappedTokenToTokenInfo(precalculateWrappedErc20); + + expect(newTokenInfo.originNetwork).to.be.equal(networkIDRollup); + expect(newTokenInfo.originTokenAddress).to.be.equal(tokenAddress); + expect(await polygonZkEVMBridgeContract.getTokenWrappedAddress(networkIDRollup, tokenAddress)).to.be.equal( + precalculateWrappedErc20 + ); + expect(await polygonZkEVMBridgeContract.getTokenWrappedAddress(networkIDRollup, tokenAddress)).to.be.equal( + precalculateWrappedErc20 + ); + + expect(await polygonZkEVMBridgeContract.tokenInfoToWrappedToken(salt)).to.be.equal(precalculateWrappedErc20); + + // Check the wrapper info + expect(await newWrappedToken.name()).to.be.equal(tokenName); + expect(await newWrappedToken.symbol()).to.be.equal(tokenSymbol); + expect(await newWrappedToken.decimals()).to.be.equal(decimals); + + // Can't claim because nullifier + await expect( + polygonZkEVMBridgeContract.claimAsset( + proofLocal, + proofRollup, + globalIndex, + mainnetExitRoot, + rollupExitRootSC, + originNetwork, + tokenAddress, + destinationNetwork, + destinationAddress, + amount, + metadata + ) + ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "AlreadyClaimed"); + expect(true).to.be.equal(await polygonZkEVMBridgeContract.isClaimed(indexLocal, indexRollup + 1)); + + expect(await newWrappedToken.totalSupply()).to.be.equal(amount); + + // Claim again the other leaf to mint tokens + const index2 = 1; + const proof2 = merkleTreeLocal.getProofTreeByIndex(index2); + + expect(verifyMerkleProof(leafValue, proof2, index2, rootLocalRollup)).to.be.equal(true); + expect(verifyMerkleProof(rootLocalRollup, proofRollup, indexRollup, rollupExitRootSC)).to.be.equal(true); + + const globalIndex2 = computeGlobalIndex(index2, indexRollup, false); + await expect( + polygonZkEVMBridgeContract.claimAsset( + proof2, + proofRollup, + globalIndex2, + mainnetExitRoot, + rollupExitRootSC, + originNetwork, + tokenAddress, + destinationNetwork, + destinationAddress, + amount, + metadata + ) + ) + .to.emit(polygonZkEVMBridgeContract, "ClaimEvent") + .withArgs(globalIndex2, originNetwork, tokenAddress, destinationAddress, amount) + .to.emit(newWrappedToken, "Transfer") + .withArgs(ethers.ZeroAddress, destinationAddress, amount); + + // Burn Tokens + const depositCount = await polygonZkEVMBridgeContract.depositCount(); + const wrappedTokenAddress = newWrappedToken.target; + const newDestinationNetwork = networkIDRollup; + + const rollupExitRoot = await polygonZkEVMGlobalExitRoot.lastRollupExitRoot(); + + // create a new deposit + await expect(newWrappedToken.approve(polygonZkEVMBridgeContract.target, amount)) + .to.emit(newWrappedToken, "Approval") + .withArgs(deployer.address, polygonZkEVMBridgeContract.target, amount); + + /* + * pre compute root merkle tree in Js + * const height = 32; + */ + const merkleTreeMainnet = new MerkleTreeBridge(height); + // Imporant calcualte leaf with origin token address no wrapped token address + const originTokenAddress = tokenAddress; + const metadataMainnet = metadata; // since the token does not belong to this network + const metadataHashMainnet = ethers.solidityPackedKeccak256(["bytes"], [metadataMainnet]); + + const leafValueMainnet = getLeafValue( + LEAF_TYPE_ASSET, + originNetwork, + originTokenAddress, + newDestinationNetwork, + destinationAddress, + amount, + metadataHashMainnet + ); + const leafValueMainnetSC = await polygonZkEVMBridgeContract.getLeafValue( + LEAF_TYPE_ASSET, + originNetwork, + originTokenAddress, + newDestinationNetwork, + destinationAddress, + amount, + metadataHashMainnet + ); + + expect(leafValueMainnet).to.be.equal(leafValueMainnetSC); + merkleTreeMainnet.add(leafValueMainnet); + const rootJSMainnet = merkleTreeMainnet.getRoot(); + + // Tokens are burnt + expect(await newWrappedToken.totalSupply()).to.be.equal(amount * 2n); + expect(await newWrappedToken.balanceOf(destinationAddress)).to.be.equal(amount * 2n); + await expect( + polygonZkEVMBridgeContract.bridgeAsset( + newDestinationNetwork, + destinationAddress, + amount, + wrappedTokenAddress, + true, + "0x" + ) + ) + .to.emit(polygonZkEVMBridgeContract, "BridgeEvent") + .withArgs( + LEAF_TYPE_ASSET, + originNetwork, + originTokenAddress, + newDestinationNetwork, + destinationAddress, + amount, + metadataMainnet, + depositCount + ) + .to.emit(polygonZkEVMGlobalExitRoot, "UpdateGlobalExitRoot") + .withArgs(rootJSMainnet, rollupExitRoot) + .to.emit(newWrappedToken, "Transfer") + .withArgs(deployer.address, ethers.ZeroAddress, amount); + + expect(await newWrappedToken.totalSupply()).to.be.equal(amount); + expect(await newWrappedToken.balanceOf(deployer.address)).to.be.equal(amount); + expect(await newWrappedToken.balanceOf(polygonZkEVMBridgeContract.target)).to.be.equal(0); + + // check merkle root with SC + const rootSCMainnet = await polygonZkEVMBridgeContract.getRoot(); + expect(rootSCMainnet).to.be.equal(rootJSMainnet); + + // check merkle proof + const proofMainnet = merkleTreeMainnet.getProofTreeByIndex(0); + const indexMainnet = 0; + + // verify merkle proof + expect(verifyMerkleProof(leafValueMainnet, proofMainnet, indexMainnet, rootSCMainnet)).to.be.equal(true); + expect( + await polygonZkEVMBridgeContract.verifyMerkleProof( + leafValueMainnet, + proofMainnet, + indexMainnet, + rootSCMainnet + ) + ).to.be.equal(true); + + const computedGlobalExitRoot2 = calculateGlobalExitRoot(rootJSMainnet, rollupExitRoot); + expect(computedGlobalExitRoot2).to.be.equal(await polygonZkEVMGlobalExitRoot.getLastGlobalExitRoot()); + }); + + it("should PolygonZkEVMBridge and sync the current root with events", async () => { + const depositCount = await polygonZkEVMBridgeContract.depositCount(); + const originNetwork = networkIDMainnet; + const tokenAddress = ethers.ZeroAddress; // gasToken + const amount = ethers.parseEther("10"); + const destinationNetwork = networkIDRollup; + const destinationAddress = deployer.address; + + const metadata = "0x"; // since is ether does not have metadata + + // create 3 new deposit + await expect( + polygonZkEVMBridgeContract.bridgeAsset( + destinationNetwork, + destinationAddress, + amount, + tokenAddress, + true, + "0x", + {value: amount} + ) + ) + .to.emit(polygonZkEVMBridgeContract, "BridgeEvent") + .withArgs( + LEAF_TYPE_ASSET, + originNetwork, + gasTokenAddress, + destinationNetwork, + destinationAddress, + amount, + gasTokenMetadata, + depositCount + ); + + await expect( + polygonZkEVMBridgeContract.bridgeAsset( + destinationNetwork, + destinationAddress, + amount, + tokenAddress, + true, + "0x", + {value: amount} + ) + ) + .to.emit(polygonZkEVMBridgeContract, "BridgeEvent") + .withArgs( + LEAF_TYPE_ASSET, + originNetwork, + gasTokenAddress, + destinationNetwork, + destinationAddress, + amount, + gasTokenMetadata, + depositCount + 1n + ); + + await expect( + polygonZkEVMBridgeContract.bridgeAsset( + destinationNetwork, + destinationAddress, + amount, + tokenAddress, + true, + "0x", + {value: amount} + ) + ) + .to.emit(polygonZkEVMBridgeContract, "BridgeEvent") + .withArgs( + LEAF_TYPE_ASSET, + originNetwork, + gasTokenAddress, + destinationNetwork, + destinationAddress, + amount, + gasTokenMetadata, + depositCount + 2n + ); + + // Prepare merkle tree + const height = 32; + const merkleTree = new MerkleTreeBridge(height); + + // Get the deposit's events + const filter = polygonZkEVMBridgeContract.filters.BridgeEvent( + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined + ); + const events = await polygonZkEVMBridgeContract.queryFilter(filter, 0, "latest"); + events.forEach((e) => { + const {args} = e; + const leafValue = getLeafValue( + args.leafType, + args.originNetwork, + args.originAddress, + args.destinationNetwork, + args.destinationAddress, + args.amount, + ethers.solidityPackedKeccak256(["bytes"], [args.metadata]) + ); + merkleTree.add(leafValue); + }); + + // Check merkle root with SC + const rootSC = await polygonZkEVMBridgeContract.getRoot(); + const rootJS = merkleTree.getRoot(); + + expect(rootSC).to.be.equal(rootJS); + }); + + it("should claim testing all the asserts", async () => { + // Add a claim leaf to rollup exit tree + const originNetwork = networkIDMainnet; + const tokenAddress = polTokenContract.target; + const amount = ethers.parseEther("10"); + const destinationNetwork = networkIDMainnet; + const destinationAddress = deployer.address; + + const metadata = metadataToken; + const metadataHash = ethers.solidityPackedKeccak256(["bytes"], [metadata]); + + const mainnetExitRoot = await polygonZkEVMGlobalExitRoot.lastMainnetExitRoot(); + + // compute root merkle tree in Js + const height = 32; + const merkleTree = new MerkleTreeBridge(height); + const leafValue = getLeafValue( + LEAF_TYPE_ASSET, + originNetwork, + tokenAddress, + destinationNetwork, + destinationAddress, + amount, + metadataHash + ); + merkleTree.add(leafValue); + + // check merkle root with SC + const rootJSRollup = merkleTree.getRoot(); + + // Try claim with 10 rollup leafs + const merkleTreeRollup = new MerkleTreeBridge(height); + merkleTreeRollup.add(rootJSRollup); + const rollupRoot = merkleTreeRollup.getRoot(); + + // add rollup Merkle root + await expect(polygonZkEVMGlobalExitRoot.connect(rollupManager).updateExitRoot(rollupRoot)) + .to.emit(polygonZkEVMGlobalExitRoot, "UpdateGlobalExitRoot") + .withArgs(mainnetExitRoot, rollupRoot); + + // check roots + const rollupExitRootSC = await polygonZkEVMGlobalExitRoot.lastRollupExitRoot(); + expect(rollupExitRootSC).to.be.equal(rollupRoot); + + const computedGlobalExitRoot = calculateGlobalExitRoot(mainnetExitRoot, rollupExitRootSC); + expect(computedGlobalExitRoot).to.be.equal(await polygonZkEVMGlobalExitRoot.getLastGlobalExitRoot()); + + // check merkle proof + const index = 0; + const proofLocal = merkleTree.getProofTreeByIndex(0); + const proofRollup = merkleTreeRollup.getProofTreeByIndex(0); + + // verify merkle proof + expect(verifyMerkleProof(leafValue, proofLocal, index, rootJSRollup)).to.be.equal(true); + expect( + await polygonZkEVMBridgeContract.verifyMerkleProof(leafValue, proofLocal, index, rootJSRollup) + ).to.be.equal(true); + + const globalIndex = computeGlobalIndex(index, index, false); + // Can't claim without tokens + await expect( + polygonZkEVMBridgeContract.claimAsset( + proofLocal, + proofRollup, + globalIndex, + mainnetExitRoot, + rollupExitRootSC, + originNetwork, + tokenAddress, + destinationNetwork, + destinationAddress, + amount, + metadata + ) + ).to.be.reverted; + + await setBalance(polygonZkEVMBridgeContract.target as any, amount); + + // Check Destination network does not match assert + // await expect( + // polygonZkEVMBridgeContract.claimAsset( + // proofLocal, + // proofRollup, + // globalIndex, + // mainnetExitRoot, + // rollupExitRootSC, + // originNetwork, + // tokenAddress, + // destinationNetwork, + // destinationAddress, + // amount, + // metadata + // ) + // ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "DestinationNetworkInvalid"); + + // Check GlobalExitRoot invalid assert + await expect( + polygonZkEVMBridgeContract.claimAsset( + proofLocal, + proofRollup, + globalIndex, + mainnetExitRoot, + mainnetExitRoot, + originNetwork, + tokenAddress, + destinationNetwork, + destinationAddress, + amount, + metadata + ) + ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "GlobalExitRootInvalid"); + + // Check Invalid smt proof assert + await expect( + polygonZkEVMBridgeContract.claimAsset( + proofLocal, + proofRollup, + globalIndex + 1n, + mainnetExitRoot, + rollupExitRootSC, + originNetwork, + tokenAddress, + destinationNetwork, + destinationAddress, + amount, + metadata + ) + ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "InvalidSmtProof"); + + await expect( + polygonZkEVMBridgeContract.claimAsset( + proofLocal, + proofRollup, + globalIndex, + mainnetExitRoot, + rollupExitRootSC, + originNetwork, + tokenAddress, + destinationNetwork, + destinationAddress, + amount, + metadata + ) + ) + .to.emit(polygonZkEVMBridgeContract, "ClaimEvent") + .withArgs(index, originNetwork, tokenAddress, destinationAddress, amount); + + // Check Already claimed_claim + await expect( + polygonZkEVMBridgeContract.claimAsset( + proofLocal, + proofRollup, + globalIndex, + mainnetExitRoot, + rollupExitRootSC, + originNetwork, + tokenAddress, + destinationNetwork, + destinationAddress, + amount, + metadata + ) + ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "AlreadyClaimed"); + }); + + it("should claim ether", async () => { + // Add a claim leaf to rollup exit tree + const originNetwork = networkIDMainnet; + const tokenAddress = ethers.ZeroAddress; // ether + const amount = ethers.parseEther("10"); + const destinationNetwork = networkIDMainnet; + const destinationAddress = deployer.address; + + const metadata = "0x"; // since is ether does not have metadata + const metadataHash = ethers.solidityPackedKeccak256(["bytes"], [metadata]); + + const mainnetExitRoot = await polygonZkEVMGlobalExitRoot.lastMainnetExitRoot(); + + // compute root merkle tree in Js + const height = 32; + const merkleTree = new MerkleTreeBridge(height); + const leafValue = getLeafValue( + LEAF_TYPE_ASSET, + originNetwork, + tokenAddress, + destinationNetwork, + destinationAddress, + amount, + metadataHash + ); + merkleTree.add(leafValue); + + // check merkle root with SC + const rootJSRollup = merkleTree.getRoot(); + const merkleTreeRollup = new MerkleTreeBridge(height); + merkleTreeRollup.add(rootJSRollup); + const rollupRoot = merkleTreeRollup.getRoot(); + + // add rollup Merkle root + await expect(polygonZkEVMGlobalExitRoot.connect(rollupManager).updateExitRoot(rollupRoot)) + .to.emit(polygonZkEVMGlobalExitRoot, "UpdateGlobalExitRoot") + .withArgs(mainnetExitRoot, rollupRoot); + + // check roots + const rollupExitRootSC = await polygonZkEVMGlobalExitRoot.lastRollupExitRoot(); + expect(rollupExitRootSC).to.be.equal(rollupRoot); + + const computedGlobalExitRoot = calculateGlobalExitRoot(mainnetExitRoot, rollupExitRootSC); + expect(computedGlobalExitRoot).to.be.equal(await polygonZkEVMGlobalExitRoot.getLastGlobalExitRoot()); + + // check merkle proof + const index = 0; + const proofLocal = merkleTree.getProofTreeByIndex(0); + const proofRollup = merkleTreeRollup.getProofTreeByIndex(0); + const globalIndex = computeGlobalIndex(index, index, false); + + // verify merkle proof + expect(verifyMerkleProof(leafValue, proofLocal, index, rootJSRollup)).to.be.equal(true); + expect( + await polygonZkEVMBridgeContract.verifyMerkleProof(leafValue, proofLocal, index, rootJSRollup) + ).to.be.equal(true); + + // claim weth + await expect( + polygonZkEVMBridgeContract.claimAsset( + proofLocal, + proofRollup, + globalIndex, + mainnetExitRoot, + rollupExitRootSC, + originNetwork, + tokenAddress, + destinationNetwork, + destinationAddress, + amount, + metadata + ) + ) + .to.emit(polygonZkEVMBridgeContract, "ClaimEvent") + .withArgs(index, originNetwork, tokenAddress, destinationAddress, amount) + .to.emit(WETHToken, "Transfer") + .withArgs(ethers.ZeroAddress, deployer.address, amount); + + // Check balances after claim + expect(await WETHToken.balanceOf(deployer.address)).to.be.equal(amount); + expect(await WETHToken.totalSupply()).to.be.equal(amount); + + // Can't claim because nullifier + await expect( + polygonZkEVMBridgeContract.claimAsset( + proofLocal, + proofRollup, + globalIndex, + mainnetExitRoot, + rollupExitRootSC, + originNetwork, + tokenAddress, + destinationNetwork, + destinationAddress, + amount, + metadata + ) + ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "AlreadyClaimed"); + }); + + it("should claim message", async () => { + // Add a claim leaf to rollup exit tree + const originNetwork = networkIDMainnet; + const tokenAddress = ethers.ZeroAddress; // ether + const amount = ethers.parseEther("10"); + const destinationNetwork = networkIDMainnet; + const destinationAddress = deployer.address; + + const metadata = "0x176923791298713271763697869132"; // since is ether does not have metadata + const metadataHash = ethers.solidityPackedKeccak256(["bytes"], [metadata]); + + const mainnetExitRoot = await polygonZkEVMGlobalExitRoot.lastMainnetExitRoot(); + + // compute root merkle tree in Js + const height = 32; + const merkleTree = new MerkleTreeBridge(height); + const leafValue = getLeafValue( + LEAF_TYPE_MESSAGE, + originNetwork, + tokenAddress, + destinationNetwork, + destinationAddress, + amount, + metadataHash + ); + merkleTree.add(leafValue); + + // check merkle root with SC + const rootJSRollup = merkleTree.getRoot(); + const merkleTreeRollup = new MerkleTreeBridge(height); + merkleTreeRollup.add(rootJSRollup); + const rollupRoot = merkleTreeRollup.getRoot(); + + // add rollup Merkle root + await expect(polygonZkEVMGlobalExitRoot.connect(rollupManager).updateExitRoot(rollupRoot)) + .to.emit(polygonZkEVMGlobalExitRoot, "UpdateGlobalExitRoot") + .withArgs(mainnetExitRoot, rollupRoot); + + // check roots + const rollupExitRootSC = await polygonZkEVMGlobalExitRoot.lastRollupExitRoot(); + expect(rollupExitRootSC).to.be.equal(rollupRoot); + + const computedGlobalExitRoot = calculateGlobalExitRoot(mainnetExitRoot, rollupExitRootSC); + expect(computedGlobalExitRoot).to.be.equal(await polygonZkEVMGlobalExitRoot.getLastGlobalExitRoot()); + + // check merkle proof + const index = 0; + const proofLocal = merkleTree.getProofTreeByIndex(0); + const proofRollup = merkleTreeRollup.getProofTreeByIndex(0); + const globalIndex = computeGlobalIndex(index, index, false); + + // verify merkle proof + expect(verifyMerkleProof(leafValue, proofLocal, index, rootJSRollup)).to.be.equal(true); + expect( + await polygonZkEVMBridgeContract.verifyMerkleProof(leafValue, proofLocal, index, rootJSRollup) + ).to.be.equal(true); + + /* + * claim + * Can't claim a message as an assets + */ + await expect( + polygonZkEVMBridgeContract.claimAsset( + proofLocal, + proofRollup, + globalIndex, + mainnetExitRoot, + rollupExitRootSC, + originNetwork, + tokenAddress, + destinationNetwork, + destinationAddress, + amount, + metadata + ) + ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "InvalidSmtProof"); + + const balanceDeployer = await ethers.provider.getBalance(deployer.address); + + // Check mainnet destination assert + await expect( + polygonZkEVMBridgeContract.claimAsset( + proofLocal, + proofRollup, + globalIndex, + mainnetExitRoot, + rollupExitRootSC, + originNetwork, + tokenAddress, + destinationNetwork, + destinationAddress, + amount, + metadata + ) + ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "InvalidSmtProof"); + + await expect( + polygonZkEVMBridgeContract.claimMessage( + proofLocal, + proofRollup, + globalIndex, + mainnetExitRoot, + rollupExitRootSC, + originNetwork, + tokenAddress, + destinationNetwork, + destinationAddress, + amount, + metadata + ) + ) + .to.emit(polygonZkEVMBridgeContract, "ClaimEvent") + .withArgs(index, originNetwork, tokenAddress, destinationAddress, amount) + .to.emit(WETHToken, "Transfer") + .withArgs(ethers.ZeroAddress, deployer.address, amount); + + // Check balances after claim + expect(await WETHToken.balanceOf(deployer.address)).to.be.equal(amount); + expect(await WETHToken.totalSupply()).to.be.equal(amount); + + // Can't claim because nullifier + await expect( + polygonZkEVMBridgeContract.claimMessage( + proofLocal, + proofRollup, + globalIndex, + mainnetExitRoot, + rollupExitRootSC, + originNetwork, + tokenAddress, + destinationNetwork, + destinationAddress, + amount, + metadata + ) + ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "AlreadyClaimed"); + }); +}); diff --git a/test/contractsv2/BridgeL2SovereignChain.test.ts b/test/contractsv2/BridgeL2SovereignChain.test.ts index adc080fca..b27e011c3 100644 --- a/test/contractsv2/BridgeL2SovereignChain.test.ts +++ b/test/contractsv2/BridgeL2SovereignChain.test.ts @@ -4,7 +4,7 @@ import { VerifierRollupHelperMock, ERC20PermitMock, PolygonRollupManagerMock, - PolygonZkEVMGlobalExitRoot, + GlobalExitRootManagerL2SovereignChain, BridgeL2SovereignChain, TokenWrapped, } from "../../typechain-types"; @@ -27,12 +27,12 @@ function computeGlobalIndex(indexLocal: any, indexRollup: any, isMainnet: Boolea } } -describe("PolygonZkEVMBridge Contract", () => { +describe("BridgeL2SovereignChain Contract", () => { upgrades.silenceWarnings(); - let polygonZkEVMBridgeContract: BridgeL2SovereignChain; + let sovereignChainBridgeContract: BridgeL2SovereignChain; let polTokenContract: ERC20PermitMock; - let polygonZkEVMGlobalExitRoot: PolygonZkEVMGlobalExitRoot; + let sovereignChainGlobalExitRoot: GlobalExitRootManagerL2SovereignChain; let deployer: any; let rollupManager: any; @@ -49,35 +49,36 @@ describe("PolygonZkEVMBridge Contract", () => { ); const networkIDMainnet = 0; const networkIDRollup = 1; + const networkIDRollup2 = 2; const LEAF_TYPE_ASSET = 0; const LEAF_TYPE_MESSAGE = 1; - const polygonZkEVMAddress = ethers.ZeroAddress; - beforeEach("Deploy contracts", async () => { // load signers [deployer, rollupManager, acc1, bridgeManager] = await ethers.getSigners(); - - // deploy PolygonZkEVMBridge - const polygonZkEVMBridgeFactory = await ethers.getContractFactory("BridgeL2SovereignChain"); - polygonZkEVMBridgeContract = (await upgrades.deployProxy(polygonZkEVMBridgeFactory, [], { + // Set trusted sequencer as coinbase for sovereign chains + await ethers.provider.send("hardhat_setCoinbase", [deployer.address]); + // deploy BridgeL2SovereignChain + const BridgeL2SovereignChainFactory = await ethers.getContractFactory("BridgeL2SovereignChain"); + sovereignChainBridgeContract = (await upgrades.deployProxy(BridgeL2SovereignChainFactory, [], { initializer: false, unsafeAllow: ["constructor"], })) as unknown as BridgeL2SovereignChain; // deploy global exit root manager - const PolygonZkEVMGlobalExitRootFactory = await ethers.getContractFactory("PolygonZkEVMGlobalExitRoot"); - polygonZkEVMGlobalExitRoot = await PolygonZkEVMGlobalExitRootFactory.deploy( - rollupManager.address, - polygonZkEVMBridgeContract.target + const PolygonZkEVMGlobalExitRootFactory = await ethers.getContractFactory( + "GlobalExitRootManagerL2SovereignChain" + ); + sovereignChainGlobalExitRoot = await PolygonZkEVMGlobalExitRootFactory.deploy( + sovereignChainBridgeContract.target ); - await polygonZkEVMBridgeContract.initialize( - networkIDMainnet, + await sovereignChainBridgeContract.initialize( + networkIDRollup2, ethers.ZeroAddress, // zero for ether ethers.ZeroAddress, // zero for ether - polygonZkEVMGlobalExitRoot.target, + sovereignChainGlobalExitRoot.target, rollupManager.address, "0x", bridgeManager @@ -93,18 +94,251 @@ describe("PolygonZkEVMBridge Contract", () => { ); }); + it("should Sovereign Chain bridge a remapped asset not mintable and verify merkle proof", async () => { + const depositCount = await sovereignChainBridgeContract.depositCount(); + const originNetwork = networkIDRollup; + const tokenAddress = polTokenContract.target; + const amount = ethers.parseEther("10"); + const destinationNetwork = networkIDRollup; + const destinationAddress = deployer.address; + const metadata = metadataToken; + const metadataHash = ethers.solidityPackedKeccak256(["bytes"], [metadata]); + + const rollupExitRoot = await sovereignChainGlobalExitRoot.lastRollupExitRoot(); + + // deploy sovereign + const maticTokenFactory = await ethers.getContractFactory("ERC20PermitMock"); + const sovereignToken = await maticTokenFactory.deploy( + tokenName, + tokenSymbol, + deployer.address, + tokenInitialBalance + ); + const balanceDeployer = await sovereignToken.balanceOf(deployer.address); + const balanceBridge = await sovereignToken.balanceOf(sovereignChainBridgeContract.target); + // Remap asset + // Remap not mintable token + await sovereignChainBridgeContract + .connect(bridgeManager) + .setSovereignTokenAddress(networkIDRollup, tokenAddress, sovereignToken.target, true); + // pre compute root merkle tree in Js + const height = 32; + const merkleTree = new MerkleTreeBridge(height); + const leafValue = getLeafValue( + LEAF_TYPE_ASSET, + originNetwork, + tokenAddress, + destinationNetwork, + destinationAddress, + amount, + metadataHash + ); + merkleTree.add(leafValue); + const rootJSMainnet = merkleTree.getRoot(); + + // Check insufficient allowance + await expect( + sovereignChainBridgeContract.bridgeAsset( + destinationNetwork, + destinationAddress, + amount, + sovereignToken.target, + true, + "0x" + ) + ).to.be.revertedWith("ERC20: insufficient allowance"); + // create a new deposit + await expect(sovereignToken.approve(sovereignChainBridgeContract.target, amount)) + .to.emit(sovereignToken, "Approval") + .withArgs(deployer.address, sovereignChainBridgeContract.target, amount); + await expect( + sovereignChainBridgeContract.bridgeAsset( + destinationNetwork, + destinationAddress, + amount, + sovereignToken.target, + true, + "0x" + ) + ) + .to.emit(sovereignChainBridgeContract, "BridgeEvent") + .withArgs( + LEAF_TYPE_ASSET, + networkIDRollup, + tokenAddress, + destinationNetwork, + destinationAddress, + amount, + metadata, + depositCount + ); + // Check updated exit root + expect(await sovereignChainGlobalExitRoot.lastRollupExitRoot()).to.be.equal(rootJSMainnet); + expect(await sovereignToken.balanceOf(deployer.address)).to.be.equal(balanceDeployer - amount); + expect(await sovereignToken.balanceOf(sovereignChainBridgeContract.target)).to.be.equal(balanceBridge + amount); + expect(await sovereignChainBridgeContract.lastUpdatedDepositCount()).to.be.equal(1); + + // check merkle root with SC + const rootSCMainnet = await sovereignChainBridgeContract.getRoot(); + expect(rootSCMainnet).to.be.equal(rootJSMainnet); + + // check merkle proof + const proof = merkleTree.getProofTreeByIndex(0); + const index = 0; + + // verify merkle proof + expect(verifyMerkleProof(leafValue, proof, index, rootSCMainnet)).to.be.equal(true); + expect( + await sovereignChainBridgeContract.verifyMerkleProof(leafValue, proof, index, rootSCMainnet) + ).to.be.equal(true); + + const computedGlobalExitRoot = calculateGlobalExitRoot(rootJSMainnet, rollupExitRoot); + // Insert global exit root + expect(await sovereignChainGlobalExitRoot.insertGlobalExitRoot(computedGlobalExitRoot)) + .to.emit(sovereignChainGlobalExitRoot, "InsertGlobalExitRoot") + .withArgs(computedGlobalExitRoot); + + // Check GER has value in mapping + expect(await sovereignChainGlobalExitRoot.globalExitRootMap(computedGlobalExitRoot)).to.not.be.eq(0); + + // Remove sovereign token address + await sovereignChainBridgeContract.connect(bridgeManager).removeSovereignTokenAddress(sovereignToken.target); + }); + + it("should Sovereign Chain bridge a remapped asset mintable and verify merkle proof", async () => { + const depositCount = await sovereignChainBridgeContract.depositCount(); + const originNetwork = networkIDRollup2; + const tokenAddress = polTokenContract.target; + const amount = ethers.parseEther("10"); + const destinationNetwork = networkIDRollup; + const destinationAddress = deployer.address; + const metadata = metadataToken; + const metadataHash = ethers.solidityPackedKeccak256(["bytes"], [metadata]); + + const balanceDeployer = await polTokenContract.balanceOf(deployer.address); + const balanceBridge = await polTokenContract.balanceOf(sovereignChainBridgeContract.target); + + const rollupExitRoot = await sovereignChainGlobalExitRoot.lastRollupExitRoot(); + + // create a new deposit + await expect(polTokenContract.approve(sovereignChainBridgeContract.target, amount)) + .to.emit(polTokenContract, "Approval") + .withArgs(deployer.address, sovereignChainBridgeContract.target, amount); + + // deploy sovereign + const maticTokenFactory = await ethers.getContractFactory("ERC20PermitMock"); + const sovereignToken = await maticTokenFactory.deploy( + tokenName, + tokenSymbol, + deployer.address, + tokenInitialBalance + ); + + // Remap asset + // Trigger requires + // only bridge manager + await expect( + sovereignChainBridgeContract + .connect(rollupManager) + .setSovereignTokenAddress(networkIDMainnet, tokenAddress, sovereignToken.target, false) + ).to.be.revertedWithCustomError(sovereignChainBridgeContract, "OnlyBridgeManager"); + // invalid token address + await expect( + sovereignChainBridgeContract + .connect(bridgeManager) + .setSovereignTokenAddress(networkIDMainnet, ethers.ZeroAddress, sovereignToken.target, false) + ).to.be.revertedWithCustomError(sovereignChainBridgeContract, "InvalidZeroAddress"); + // Invalid origin network + await expect( + sovereignChainBridgeContract + .connect(bridgeManager) + .setSovereignTokenAddress(networkIDRollup2, tokenAddress, sovereignToken.target, false) + ).to.be.revertedWithCustomError(sovereignChainBridgeContract, "OriginNetworkInvalid"); + await sovereignChainBridgeContract + .connect(bridgeManager) + .setSovereignTokenAddress(networkIDRollup, tokenAddress, sovereignToken.target, false); + // pre compute root merkle tree in Js + const height = 32; + const merkleTree = new MerkleTreeBridge(height); + const leafValue = getLeafValue( + LEAF_TYPE_ASSET, + originNetwork, + tokenAddress, + destinationNetwork, + destinationAddress, + amount, + metadataHash + ); + merkleTree.add(leafValue); + const rootJSMainnet = merkleTree.getRoot(); + + await expect( + sovereignChainBridgeContract.bridgeAsset( + destinationNetwork, + destinationAddress, + amount, + tokenAddress, + true, + "0x" + ) + ) + .to.emit(sovereignChainBridgeContract, "BridgeEvent") + .withArgs( + LEAF_TYPE_ASSET, + originNetwork, + tokenAddress, + destinationNetwork, + destinationAddress, + amount, + metadata, + depositCount + ); + // Check updated exit root + expect(await sovereignChainGlobalExitRoot.lastRollupExitRoot()).to.be.equal(rootJSMainnet); + expect(await polTokenContract.balanceOf(deployer.address)).to.be.equal(balanceDeployer - amount); + expect(await polTokenContract.balanceOf(sovereignChainBridgeContract.target)).to.be.equal( + balanceBridge + amount + ); + expect(await sovereignChainBridgeContract.lastUpdatedDepositCount()).to.be.equal(1); + + // check merkle root with SC + const rootSCMainnet = await sovereignChainBridgeContract.getRoot(); + expect(rootSCMainnet).to.be.equal(rootJSMainnet); + + // check merkle proof + const proof = merkleTree.getProofTreeByIndex(0); + const index = 0; + + // verify merkle proof + expect(verifyMerkleProof(leafValue, proof, index, rootSCMainnet)).to.be.equal(true); + expect( + await sovereignChainBridgeContract.verifyMerkleProof(leafValue, proof, index, rootSCMainnet) + ).to.be.equal(true); + + const computedGlobalExitRoot = calculateGlobalExitRoot(rootJSMainnet, rollupExitRoot); + // Insert global exit root + expect(await sovereignChainGlobalExitRoot.insertGlobalExitRoot(computedGlobalExitRoot)) + .to.emit(sovereignChainGlobalExitRoot, "InsertGlobalExitRoot") + .withArgs(computedGlobalExitRoot); + + // Check GER has value in mapping + expect(await sovereignChainGlobalExitRoot.globalExitRootMap(computedGlobalExitRoot)).to.not.be.eq(0); + }); + it("should check the initialize parameters", async () => { - expect(await polygonZkEVMBridgeContract.globalExitRootManager()).to.be.equal(polygonZkEVMGlobalExitRoot.target); - expect(await polygonZkEVMBridgeContract.networkID()).to.be.equal(networkIDMainnet); - expect(await polygonZkEVMBridgeContract.polygonRollupManager()).to.be.equal(rollupManager.address); + expect(await sovereignChainBridgeContract.globalExitRootManager()).to.be.equal( + sovereignChainGlobalExitRoot.target + ); + expect(await sovereignChainBridgeContract.networkID()).to.be.equal(networkIDRollup2); + expect(await sovereignChainBridgeContract.polygonRollupManager()).to.be.equal(rollupManager.address); - // cannot initialzie again + // cannot initialize again await expect( - polygonZkEVMBridgeContract.initialize( + sovereignChainBridgeContract.initialize( networkIDMainnet, ethers.ZeroAddress, // zero for ether ethers.ZeroAddress, // zero for ether - polygonZkEVMGlobalExitRoot.target, + sovereignChainGlobalExitRoot.target, rollupManager.address, "0x", bridgeManager @@ -114,30 +348,29 @@ describe("PolygonZkEVMBridge Contract", () => { it("should check bridgeMessageWETH reverts", async () => { await expect( - polygonZkEVMBridgeContract.bridgeMessageWETH(networkIDMainnet, deployer.address, 0, true, "0x") - ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "NativeTokenIsEther"); + sovereignChainBridgeContract.bridgeMessageWETH(networkIDMainnet, deployer.address, 0, true, "0x") + ).to.be.revertedWithCustomError(sovereignChainBridgeContract, "NativeTokenIsEther"); }); - it("should PolygonZkEVM bridge asset and verify merkle proof", async () => { - const depositCount = await polygonZkEVMBridgeContract.depositCount(); - const originNetwork = networkIDMainnet; + it("should Sovereign Chain bridge asset and verify merkle proof", async () => { + const depositCount = await sovereignChainBridgeContract.depositCount(); + const originNetwork = networkIDRollup2; const tokenAddress = polTokenContract.target; const amount = ethers.parseEther("10"); const destinationNetwork = networkIDRollup; const destinationAddress = deployer.address; - const metadata = metadataToken; const metadataHash = ethers.solidityPackedKeccak256(["bytes"], [metadata]); const balanceDeployer = await polTokenContract.balanceOf(deployer.address); - const balanceBridge = await polTokenContract.balanceOf(polygonZkEVMBridgeContract.target); + const balanceBridge = await polTokenContract.balanceOf(sovereignChainBridgeContract.target); - const rollupExitRoot = await polygonZkEVMGlobalExitRoot.lastRollupExitRoot(); + const rollupExitRoot = await sovereignChainGlobalExitRoot.lastRollupExitRoot(); // create a new deposit - await expect(polTokenContract.approve(polygonZkEVMBridgeContract.target, amount)) + await expect(polTokenContract.approve(sovereignChainBridgeContract.target, amount)) .to.emit(polTokenContract, "Approval") - .withArgs(deployer.address, polygonZkEVMBridgeContract.target, amount); + .withArgs(deployer.address, sovereignChainBridgeContract.target, amount); // pre compute root merkle tree in Js const height = 32; @@ -155,7 +388,7 @@ describe("PolygonZkEVMBridge Contract", () => { const rootJSMainnet = merkleTree.getRoot(); await expect( - polygonZkEVMBridgeContract.bridgeAsset( + sovereignChainBridgeContract.bridgeAsset( destinationNetwork, destinationAddress, amount, @@ -164,10 +397,10 @@ describe("PolygonZkEVMBridge Contract", () => { "0x", {value: 1} ) - ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "MsgValueNotZero"); + ).to.be.revertedWithCustomError(sovereignChainBridgeContract, "MsgValueNotZero"); await expect( - polygonZkEVMBridgeContract.bridgeAsset( + sovereignChainBridgeContract.bridgeAsset( destinationNetwork, destinationAddress, amount, @@ -176,7 +409,7 @@ describe("PolygonZkEVMBridge Contract", () => { "0x" ) ) - .to.emit(polygonZkEVMBridgeContract, "BridgeEvent") + .to.emit(sovereignChainBridgeContract, "BridgeEvent") .withArgs( LEAF_TYPE_ASSET, originNetwork, @@ -186,16 +419,17 @@ describe("PolygonZkEVMBridge Contract", () => { amount, metadata, depositCount - ) - .to.emit(polygonZkEVMGlobalExitRoot, "UpdateGlobalExitRoot") - .withArgs(rootJSMainnet, rollupExitRoot); - + ); + // Check updated exit root + expect(await sovereignChainGlobalExitRoot.lastRollupExitRoot()).to.be.equal(rootJSMainnet); expect(await polTokenContract.balanceOf(deployer.address)).to.be.equal(balanceDeployer - amount); - expect(await polTokenContract.balanceOf(polygonZkEVMBridgeContract.target)).to.be.equal(balanceBridge + amount); - expect(await polygonZkEVMBridgeContract.lastUpdatedDepositCount()).to.be.equal(1); + expect(await polTokenContract.balanceOf(sovereignChainBridgeContract.target)).to.be.equal( + balanceBridge + amount + ); + expect(await sovereignChainBridgeContract.lastUpdatedDepositCount()).to.be.equal(1); // check merkle root with SC - const rootSCMainnet = await polygonZkEVMBridgeContract.getRoot(); + const rootSCMainnet = await sovereignChainBridgeContract.getRoot(); expect(rootSCMainnet).to.be.equal(rootJSMainnet); // check merkle proof @@ -204,17 +438,23 @@ describe("PolygonZkEVMBridge Contract", () => { // verify merkle proof expect(verifyMerkleProof(leafValue, proof, index, rootSCMainnet)).to.be.equal(true); - expect(await polygonZkEVMBridgeContract.verifyMerkleProof(leafValue, proof, index, rootSCMainnet)).to.be.equal( - true - ); + expect( + await sovereignChainBridgeContract.verifyMerkleProof(leafValue, proof, index, rootSCMainnet) + ).to.be.equal(true); const computedGlobalExitRoot = calculateGlobalExitRoot(rootJSMainnet, rollupExitRoot); - expect(computedGlobalExitRoot).to.be.equal(await polygonZkEVMGlobalExitRoot.getLastGlobalExitRoot()); + // Insert global exit root + expect(await sovereignChainGlobalExitRoot.insertGlobalExitRoot(computedGlobalExitRoot)) + .to.emit(sovereignChainGlobalExitRoot, "InsertGlobalExitRoot") + .withArgs(computedGlobalExitRoot); + + // Check GER has value in mapping + expect(await sovereignChainGlobalExitRoot.globalExitRootMap(computedGlobalExitRoot)).to.not.be.eq(0); }); - it("should PolygonZkEVMBridge message and verify merkle proof", async () => { - const depositCount = await polygonZkEVMBridgeContract.depositCount(); - const originNetwork = networkIDMainnet; + it("should message at Sovereign chain and verify merkle proof", async () => { + const depositCount = await sovereignChainBridgeContract.depositCount(); + const originNetwork = networkIDRollup2; const originAddress = deployer.address; const amount = ethers.parseEther("10"); const destinationNetwork = networkIDRollup; @@ -222,7 +462,7 @@ describe("PolygonZkEVMBridge Contract", () => { const metadata = metadataToken; const metadataHash = ethers.solidityPackedKeccak256(["bytes"], [metadata]); - const rollupExitRoot = await polygonZkEVMGlobalExitRoot.lastRollupExitRoot(); + const rollupExitRoot = await sovereignChainGlobalExitRoot.lastRollupExitRoot(); // pre compute root merkle tree in Js const height = 32; @@ -240,15 +480,15 @@ describe("PolygonZkEVMBridge Contract", () => { const rootJSMainnet = merkleTree.getRoot(); await expect( - polygonZkEVMBridgeContract.bridgeMessage(networkIDMainnet, destinationAddress, true, "0x") - ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "DestinationNetworkInvalid"); + sovereignChainBridgeContract.bridgeMessage(networkIDRollup2, destinationAddress, true, "0x") + ).to.be.revertedWithCustomError(sovereignChainBridgeContract, "DestinationNetworkInvalid"); await expect( - polygonZkEVMBridgeContract.bridgeMessage(destinationNetwork, destinationAddress, true, metadata, { + sovereignChainBridgeContract.bridgeMessage(destinationNetwork, destinationAddress, true, metadata, { value: amount, }) ) - .to.emit(polygonZkEVMBridgeContract, "BridgeEvent") + .to.emit(sovereignChainBridgeContract, "BridgeEvent") .withArgs( LEAF_TYPE_MESSAGE, originNetwork, @@ -261,7 +501,7 @@ describe("PolygonZkEVMBridge Contract", () => { ); // check merkle root with SC - const rootSCMainnet = await polygonZkEVMBridgeContract.getRoot(); + const rootSCMainnet = await sovereignChainBridgeContract.getRoot(); expect(rootSCMainnet).to.be.equal(rootJSMainnet); // check merkle proof @@ -270,17 +510,23 @@ describe("PolygonZkEVMBridge Contract", () => { // verify merkle proof expect(verifyMerkleProof(leafValue, proof, index, rootSCMainnet)).to.be.equal(true); - expect(await polygonZkEVMBridgeContract.verifyMerkleProof(leafValue, proof, index, rootSCMainnet)).to.be.equal( - true - ); + expect( + await sovereignChainBridgeContract.verifyMerkleProof(leafValue, proof, index, rootSCMainnet) + ).to.be.equal(true); const computedGlobalExitRoot = calculateGlobalExitRoot(rootJSMainnet, rollupExitRoot); - expect(computedGlobalExitRoot).to.be.equal(await polygonZkEVMGlobalExitRoot.getLastGlobalExitRoot()); + // Insert global exit root + expect(await sovereignChainGlobalExitRoot.insertGlobalExitRoot(computedGlobalExitRoot)) + .to.emit(sovereignChainGlobalExitRoot, "InsertGlobalExitRoot") + .withArgs(computedGlobalExitRoot); + + // Check GER has value in mapping + expect(await sovereignChainGlobalExitRoot.globalExitRootMap(computedGlobalExitRoot)).to.not.be.eq(0); }); - it("should PolygonZkEVM bridge asset and message to check global exit root updates", async () => { - const depositCount = await polygonZkEVMBridgeContract.depositCount(); - const originNetwork = networkIDMainnet; + it("should bridge asset and message to sovereign chain to check global exit root updates", async () => { + const depositCount = await sovereignChainBridgeContract.depositCount(); + const originNetwork = networkIDRollup2; const tokenAddress = polTokenContract.target; const amount = ethers.parseEther("10"); const destinationNetwork = networkIDRollup; @@ -290,14 +536,14 @@ describe("PolygonZkEVMBridge Contract", () => { const metadataHash = ethers.solidityPackedKeccak256(["bytes"], [metadata]); const balanceDeployer = await polTokenContract.balanceOf(deployer.address); - const balanceBridge = await polTokenContract.balanceOf(polygonZkEVMBridgeContract.target); + const balanceBridge = await polTokenContract.balanceOf(sovereignChainBridgeContract.target); - const rollupExitRoot = await polygonZkEVMGlobalExitRoot.lastRollupExitRoot(); + const rollupExitRoot = await sovereignChainGlobalExitRoot.lastRollupExitRoot(); // create a new deposit - await expect(polTokenContract.approve(polygonZkEVMBridgeContract.target, amount)) + await expect(polTokenContract.approve(sovereignChainBridgeContract.target, amount)) .to.emit(polTokenContract, "Approval") - .withArgs(deployer.address, polygonZkEVMBridgeContract.target, amount); + .withArgs(deployer.address, sovereignChainBridgeContract.target, amount); // pre compute root merkle tree in Js const height = 32; @@ -315,7 +561,7 @@ describe("PolygonZkEVMBridge Contract", () => { const rootJSMainnet = merkleTree.getRoot(); await expect( - polygonZkEVMBridgeContract.bridgeAsset( + sovereignChainBridgeContract.bridgeAsset( destinationNetwork, destinationAddress, amount, @@ -324,7 +570,7 @@ describe("PolygonZkEVMBridge Contract", () => { "0x" ) ) - .to.emit(polygonZkEVMBridgeContract, "BridgeEvent") + .to.emit(sovereignChainBridgeContract, "BridgeEvent") .withArgs( LEAF_TYPE_ASSET, originNetwork, @@ -337,34 +583,35 @@ describe("PolygonZkEVMBridge Contract", () => { ); expect(await polTokenContract.balanceOf(deployer.address)).to.be.equal(balanceDeployer - amount); - expect(await polTokenContract.balanceOf(polygonZkEVMBridgeContract.target)).to.be.equal(balanceBridge + amount); - expect(await polygonZkEVMBridgeContract.lastUpdatedDepositCount()).to.be.equal(0); - expect(await polygonZkEVMGlobalExitRoot.lastMainnetExitRoot()).to.be.equal(ethers.ZeroHash); + expect(await polTokenContract.balanceOf(sovereignChainBridgeContract.target)).to.be.equal( + balanceBridge + amount + ); + expect(await sovereignChainBridgeContract.lastUpdatedDepositCount()).to.be.equal(0); // check merkle root with SC - const rootSCMainnet = await polygonZkEVMBridgeContract.getRoot(); + const rootSCMainnet = await sovereignChainBridgeContract.getRoot(); expect(rootSCMainnet).to.be.equal(rootJSMainnet); // Update global exit root - await expect(polygonZkEVMBridgeContract.updateGlobalExitRoot()) - .to.emit(polygonZkEVMGlobalExitRoot, "UpdateGlobalExitRoot") - .withArgs(rootJSMainnet, rollupExitRoot); - - // no state changes since there are not any deposit pending to be updated - await polygonZkEVMBridgeContract.updateGlobalExitRoot(); - expect(await polygonZkEVMBridgeContract.lastUpdatedDepositCount()).to.be.equal(1); - expect(await polygonZkEVMGlobalExitRoot.lastMainnetExitRoot()).to.be.equal(rootJSMainnet); + await sovereignChainBridgeContract.updateGlobalExitRoot(); + expect(await sovereignChainBridgeContract.lastUpdatedDepositCount()).to.be.equal(1); const computedGlobalExitRoot = calculateGlobalExitRoot(rootJSMainnet, rollupExitRoot); - expect(computedGlobalExitRoot).to.be.equal(await polygonZkEVMGlobalExitRoot.getLastGlobalExitRoot()); + // Insert global exit root + expect(await sovereignChainGlobalExitRoot.insertGlobalExitRoot(computedGlobalExitRoot)) + .to.emit(sovereignChainGlobalExitRoot, "InsertGlobalExitRoot") + .withArgs(computedGlobalExitRoot); + + // Check GER has value in mapping + expect(await sovereignChainGlobalExitRoot.globalExitRootMap(computedGlobalExitRoot)).to.not.be.eq(0); // bridge message await expect( - polygonZkEVMBridgeContract.bridgeMessage(destinationNetwork, destinationAddress, false, metadata, { + sovereignChainBridgeContract.bridgeMessage(destinationNetwork, destinationAddress, false, metadata, { value: amount, }) ) - .to.emit(polygonZkEVMBridgeContract, "BridgeEvent") + .to.emit(sovereignChainBridgeContract, "BridgeEvent") .withArgs( LEAF_TYPE_MESSAGE, originNetwork, @@ -375,22 +622,18 @@ describe("PolygonZkEVMBridge Contract", () => { metadata, 1 ); - expect(await polygonZkEVMBridgeContract.lastUpdatedDepositCount()).to.be.equal(1); - expect(await polygonZkEVMGlobalExitRoot.lastMainnetExitRoot()).to.be.equal(rootJSMainnet); + expect(await sovereignChainBridgeContract.lastUpdatedDepositCount()).to.be.equal(1); // Update global exit root - await expect(polygonZkEVMBridgeContract.updateGlobalExitRoot()).to.emit( - polygonZkEVMGlobalExitRoot, - "UpdateGlobalExitRoot" - ); + await sovereignChainBridgeContract.updateGlobalExitRoot(); - expect(await polygonZkEVMBridgeContract.lastUpdatedDepositCount()).to.be.equal(2); - expect(await polygonZkEVMGlobalExitRoot.lastMainnetExitRoot()).to.not.be.equal(rootJSMainnet); + expect(await sovereignChainBridgeContract.lastUpdatedDepositCount()).to.be.equal(2); + expect(await sovereignChainGlobalExitRoot.lastRollupExitRoot()).to.not.be.equal(rootJSMainnet); // Just to have the metric of a low cost bridge Asset const tokenAddress2 = ethers.ZeroAddress; // Ether const amount2 = ethers.parseEther("10"); - await polygonZkEVMBridgeContract.bridgeAsset( + await sovereignChainBridgeContract.bridgeAsset( destinationNetwork, destinationAddress, amount2, @@ -402,182 +645,16 @@ describe("PolygonZkEVMBridge Contract", () => { }); it("should claim tokens from Mainnet to Mainnet", async () => { - const originNetwork = networkIDMainnet; - const tokenAddress = polTokenContract.target; - const amount = ethers.parseEther("10"); - const destinationNetwork = networkIDMainnet; - const destinationAddress = acc1.address; - - const metadata = metadataToken; - const metadataHash = ethers.solidityPackedKeccak256(["bytes"], [metadata]); - - const rollupExitRoot = await polygonZkEVMGlobalExitRoot.lastRollupExitRoot(); - - // compute root merkle tree in Js - const height = 32; - const merkleTreeLocal = new MerkleTreeBridge(height); - const leafValue = getLeafValue( - LEAF_TYPE_ASSET, - originNetwork, - tokenAddress, - destinationNetwork, - destinationAddress, - amount, - metadataHash - ); - merkleTreeLocal.add(leafValue); - - const mainnetExitRoot = merkleTreeLocal.getRoot(); - const indexRollup = 0; - - // check only rollup account with update rollup exit root - await expect(polygonZkEVMGlobalExitRoot.updateExitRoot(mainnetExitRoot)).to.be.revertedWithCustomError( - polygonZkEVMGlobalExitRoot, - "OnlyAllowedContracts" - ); - - // add rollup Merkle root - await ethers.provider.send("hardhat_impersonateAccount", [polygonZkEVMBridgeContract.target]); - const bridgemoCK = await ethers.getSigner(polygonZkEVMBridgeContract.target as any); - - // await deployer.sendTransaction({ - // to: bridgemoCK.address, - // value: ethers.parseEther("1"), - // }); - - await expect(polygonZkEVMGlobalExitRoot.connect(bridgemoCK).updateExitRoot(mainnetExitRoot, {gasPrice: 0})) - .to.emit(polygonZkEVMGlobalExitRoot, "UpdateGlobalExitRoot") - .withArgs(mainnetExitRoot, rollupExitRoot); - - // check roots - const rollupExitRootSC = await polygonZkEVMGlobalExitRoot.lastRollupExitRoot(); - expect(rollupExitRootSC).to.be.equal(rollupExitRoot); - const mainnetExitRootSC = await polygonZkEVMGlobalExitRoot.lastMainnetExitRoot(); - expect(mainnetExitRootSC).to.be.equal(mainnetExitRoot); - - const computedGlobalExitRoot = calculateGlobalExitRoot(mainnetExitRoot, rollupExitRootSC); - expect(computedGlobalExitRoot).to.be.equal(await polygonZkEVMGlobalExitRoot.getLastGlobalExitRoot()); - - // check merkle proof - - // Merkle proof local - const indexLocal = 0; - const proofLocal = merkleTreeLocal.getProofTreeByIndex(indexLocal); - - // verify merkle proof - expect(verifyMerkleProof(leafValue, proofLocal, indexLocal, mainnetExitRoot)).to.be.equal(true); - - const globalIndex = computeGlobalIndex(indexLocal, indexRollup, true); - - /* - * claim - * Can't claim without tokens - */ - await expect( - polygonZkEVMBridgeContract.claimAsset( - proofLocal, - proofLocal, - globalIndex, - mainnetExitRoot, - rollupExitRootSC, - originNetwork, - tokenAddress, - destinationNetwork, - destinationAddress, - amount, - metadata - ) - ).to.be.revertedWith("ERC20: transfer amount exceeds balance"); - - await expect( - polygonZkEVMBridgeContract.claimAsset( - proofLocal, - proofLocal, - globalIndex, - mainnetExitRoot, - rollupExitRootSC, - originNetwork, - tokenAddress, - networkIDRollup, - destinationAddress, - amount, - metadata - ) - ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "DestinationNetworkInvalid"); - - await expect( - polygonZkEVMBridgeContract.claimAsset( - proofLocal, - proofLocal, - globalIndex, - mainnetExitRoot, - rollupExitRootSC, - originNetwork, - tokenAddress, - destinationNetwork, - destinationAddress, - amount + 1n, - metadata - ) - ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "InvalidSmtProof"); - - // transfer tokens, then claim - await expect(polTokenContract.transfer(polygonZkEVMBridgeContract.target, amount)) - .to.emit(polTokenContract, "Transfer") - .withArgs(deployer.address, polygonZkEVMBridgeContract.target, amount); - - expect(false).to.be.equal(await polygonZkEVMBridgeContract.isClaimed(indexLocal, indexRollup + 1)); - - await expect( - polygonZkEVMBridgeContract.claimAsset( - proofLocal, - proofLocal, - globalIndex, - mainnetExitRoot, - rollupExitRootSC, - originNetwork, - tokenAddress, - destinationNetwork, - destinationAddress, - amount, - metadata - ) - ) - .to.emit(polygonZkEVMBridgeContract, "ClaimEvent") - .withArgs(globalIndex, originNetwork, tokenAddress, destinationAddress, amount) - .to.emit(polTokenContract, "Transfer") - .withArgs(polygonZkEVMBridgeContract.target, acc1.address, amount); - - // Can't claim because nullifier - await expect( - polygonZkEVMBridgeContract.claimAsset( - proofLocal, - proofLocal, - globalIndex, - mainnetExitRoot, - rollupExitRootSC, - originNetwork, - tokenAddress, - destinationNetwork, - destinationAddress, - amount, - metadata - ) - ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "AlreadyClaimed"); - expect(true).to.be.equal(await polygonZkEVMBridgeContract.isClaimed(indexLocal, indexRollup + 1)); - }); - - it("should claim tokens from Mainnet to Mainnet", async () => { - const originNetwork = networkIDMainnet; + const originNetwork = networkIDRollup2; const tokenAddress = polTokenContract.target; const amount = ethers.parseEther("10"); - const destinationNetwork = networkIDMainnet; + const destinationNetwork = networkIDRollup2; const destinationAddress = acc1.address; const metadata = metadataToken; const metadataHash = ethers.solidityPackedKeccak256(["bytes"], [metadata]); - const mainnetExitRoot = await polygonZkEVMGlobalExitRoot.lastMainnetExitRoot(); + const mainnetExitRoot = ethers.ZeroHash; // compute root merkle tree in Js const height = 32; @@ -609,25 +686,30 @@ describe("PolygonZkEVMBridge Contract", () => { const rootRollup = merkleTreeRollup.getRoot(); // check only rollup account with update rollup exit root - await expect(polygonZkEVMGlobalExitRoot.updateExitRoot(rootRollup)).to.be.revertedWithCustomError( - polygonZkEVMGlobalExitRoot, + await expect(sovereignChainGlobalExitRoot.updateExitRoot(rootRollup)).to.be.revertedWithCustomError( + sovereignChainGlobalExitRoot, "OnlyAllowedContracts" ); // add rollup Merkle root - await expect(polygonZkEVMGlobalExitRoot.connect(rollupManager).updateExitRoot(rootRollup)) - .to.emit(polygonZkEVMGlobalExitRoot, "UpdateGlobalExitRoot") - .withArgs(mainnetExitRoot, rootRollup); + await ethers.provider.send("hardhat_impersonateAccount", [sovereignChainBridgeContract.target]); + const bridgeMock = await ethers.getSigner(sovereignChainBridgeContract.target as any); + await sovereignChainGlobalExitRoot.connect(bridgeMock).updateExitRoot(rootRollup, {gasPrice: 0}); // check roots - const rollupExitRootSC = await polygonZkEVMGlobalExitRoot.lastRollupExitRoot(); + const rollupExitRootSC = await sovereignChainGlobalExitRoot.lastRollupExitRoot(); expect(rollupExitRootSC).to.be.equal(rootRollup); const computedGlobalExitRoot = calculateGlobalExitRoot(mainnetExitRoot, rollupExitRootSC); - expect(computedGlobalExitRoot).to.be.equal(await polygonZkEVMGlobalExitRoot.getLastGlobalExitRoot()); + // Insert global exit root + expect(await sovereignChainGlobalExitRoot.insertGlobalExitRoot(computedGlobalExitRoot)) + .to.emit(sovereignChainGlobalExitRoot, "InsertGlobalExitRoot") + .withArgs(computedGlobalExitRoot); - // check merkle proof + // Check GER has value in mapping + expect(await sovereignChainGlobalExitRoot.globalExitRootMap(computedGlobalExitRoot)).to.not.be.eq(0); + // check merkle proof // Merkle proof local const indexLocal = 0; const proofLocal = merkleTreeLocal.getProofTreeByIndex(indexLocal); @@ -638,7 +720,7 @@ describe("PolygonZkEVMBridge Contract", () => { // verify merkle proof expect(verifyMerkleProof(rootLocalRollup, proofRollup, indexRollup, rootRollup)).to.be.equal(true); expect( - await polygonZkEVMBridgeContract.verifyMerkleProof(rootLocalRollup, proofRollup, indexRollup, rootRollup) + await sovereignChainBridgeContract.verifyMerkleProof(rootLocalRollup, proofRollup, indexRollup, rootRollup) ).to.be.equal(true); const globalIndex = computeGlobalIndex(indexLocal, indexRollup, false); /* @@ -646,7 +728,7 @@ describe("PolygonZkEVMBridge Contract", () => { * Can't claim without tokens */ await expect( - polygonZkEVMBridgeContract.claimAsset( + sovereignChainBridgeContract.claimAsset( proofLocal, proofRollup, Number(globalIndex), @@ -662,14 +744,14 @@ describe("PolygonZkEVMBridge Contract", () => { ).to.be.revertedWith("ERC20: transfer amount exceeds balance"); // transfer tokens, then claim - await expect(polTokenContract.transfer(polygonZkEVMBridgeContract.target, amount)) + await expect(polTokenContract.transfer(sovereignChainBridgeContract.target, amount)) .to.emit(polTokenContract, "Transfer") - .withArgs(deployer.address, polygonZkEVMBridgeContract.target, amount); + .withArgs(deployer.address, sovereignChainBridgeContract.target, amount); - expect(false).to.be.equal(await polygonZkEVMBridgeContract.isClaimed(indexLocal, indexRollup + 1)); + expect(false).to.be.equal(await sovereignChainBridgeContract.isClaimed(indexLocal, indexRollup + 1)); await expect( - polygonZkEVMBridgeContract.claimAsset( + sovereignChainBridgeContract.claimAsset( proofLocal, proofRollup, globalIndex, @@ -683,14 +765,14 @@ describe("PolygonZkEVMBridge Contract", () => { metadata ) ) - .to.emit(polygonZkEVMBridgeContract, "ClaimEvent") + .to.emit(sovereignChainBridgeContract, "ClaimEvent") .withArgs(globalIndex, originNetwork, tokenAddress, destinationAddress, amount) .to.emit(polTokenContract, "Transfer") - .withArgs(polygonZkEVMBridgeContract.target, acc1.address, amount); + .withArgs(sovereignChainBridgeContract.target, acc1.address, amount); // Can't claim because nullifier await expect( - polygonZkEVMBridgeContract.claimAsset( + sovereignChainBridgeContract.claimAsset( proofLocal, proofRollup, globalIndex, @@ -703,21 +785,21 @@ describe("PolygonZkEVMBridge Contract", () => { amount, metadata ) - ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "AlreadyClaimed"); - expect(true).to.be.equal(await polygonZkEVMBridgeContract.isClaimed(indexLocal, indexRollup + 1)); + ).to.be.revertedWithCustomError(sovereignChainBridgeContract, "AlreadyClaimed"); + expect(true).to.be.equal(await sovereignChainBridgeContract.isClaimed(indexLocal, indexRollup + 1)); }); it("should claim tokens from Rollup to Mainnet", async () => { const originNetwork = networkIDRollup; const tokenAddress = polTokenContract.target; const amount = ethers.parseEther("10"); - const destinationNetwork = networkIDMainnet; + const destinationNetwork = networkIDRollup2; const destinationAddress = deployer.address; const metadata = metadataToken; const metadataHash = ethers.solidityPackedKeccak256(["bytes"], [metadata]); - const mainnetExitRoot = await polygonZkEVMGlobalExitRoot.lastMainnetExitRoot(); + const mainnetExitRoot = ethers.ZeroHash; // compute root merkle tree in Js const height = 32; @@ -745,23 +827,28 @@ describe("PolygonZkEVMBridge Contract", () => { const rootRollup = merkleTreeRollup.getRoot(); // check only rollup account with update rollup exit root - await expect(polygonZkEVMGlobalExitRoot.updateExitRoot(rootRollup)).to.be.revertedWithCustomError( - polygonZkEVMGlobalExitRoot, + await expect(sovereignChainGlobalExitRoot.updateExitRoot(rootRollup)).to.be.revertedWithCustomError( + sovereignChainGlobalExitRoot, "OnlyAllowedContracts" ); // add rollup Merkle root - await expect(polygonZkEVMGlobalExitRoot.connect(rollupManager).updateExitRoot(rootRollup)) - .to.emit(polygonZkEVMGlobalExitRoot, "UpdateGlobalExitRoot") - .withArgs(mainnetExitRoot, rootRollup); + await ethers.provider.send("hardhat_impersonateAccount", [sovereignChainBridgeContract.target]); + const bridgeMock = await ethers.getSigner(sovereignChainBridgeContract.target as any); + await sovereignChainGlobalExitRoot.connect(bridgeMock).updateExitRoot(rootRollup, {gasPrice: 0}); // check roots - const rollupExitRootSC = await polygonZkEVMGlobalExitRoot.lastRollupExitRoot(); + const rollupExitRootSC = await sovereignChainGlobalExitRoot.lastRollupExitRoot(); expect(rollupExitRootSC).to.be.equal(rootRollup); const computedGlobalExitRoot = calculateGlobalExitRoot(mainnetExitRoot, rollupExitRootSC); - expect(computedGlobalExitRoot).to.be.equal(await polygonZkEVMGlobalExitRoot.getLastGlobalExitRoot()); + // Insert global exit root + expect(await sovereignChainGlobalExitRoot.insertGlobalExitRoot(computedGlobalExitRoot)) + .to.emit(sovereignChainGlobalExitRoot, "InsertGlobalExitRoot") + .withArgs(computedGlobalExitRoot); + // Check GER has value in mapping + expect(await sovereignChainGlobalExitRoot.globalExitRootMap(computedGlobalExitRoot)).to.not.be.eq(0); // check merkle proof // Merkle proof local @@ -776,20 +863,20 @@ describe("PolygonZkEVMBridge Contract", () => { expect(verifyMerkleProof(leafValue, proofLocal, indexLocal, rootLocalRollup)).to.be.equal(true); expect(verifyMerkleProof(rootLocalRollup, proofRollup, indexRollup, rootRollup)).to.be.equal(true); expect( - await polygonZkEVMBridgeContract.verifyMerkleProof(rootLocalRollup, proofRollup, indexRollup, rootRollup) + await sovereignChainBridgeContract.verifyMerkleProof(rootLocalRollup, proofRollup, indexRollup, rootRollup) ).to.be.equal(true); const globalIndex = computeGlobalIndex(indexLocal, indexRollup, false); - expect(false).to.be.equal(await polygonZkEVMBridgeContract.isClaimed(indexLocal, indexRollup + 1)); + expect(false).to.be.equal(await sovereignChainBridgeContract.isClaimed(indexLocal, indexRollup + 1)); // claim const tokenWrappedFactory = await ethers.getContractFactory("TokenWrapped"); // create2 parameters const salt = ethers.solidityPackedKeccak256(["uint32", "address"], [networkIDRollup, tokenAddress]); - const minimalBytecodeProxy = await polygonZkEVMBridgeContract.BASE_INIT_BYTECODE_WRAPPED_TOKEN(); + const minimalBytecodeProxy = await sovereignChainBridgeContract.BASE_INIT_BYTECODE_WRAPPED_TOKEN(); const hashInitCode = ethers.solidityPackedKeccak256(["bytes", "bytes"], [minimalBytecodeProxy, metadataToken]); const precalculateWrappedErc20 = await ethers.getCreate2Address( - polygonZkEVMBridgeContract.target as string, + sovereignChainBridgeContract.target as string, salt, hashInitCode ); @@ -797,7 +884,7 @@ describe("PolygonZkEVMBridge Contract", () => { // Use precalculatedWrapperAddress and check if matches expect( - await polygonZkEVMBridgeContract.precalculatedWrapperAddress( + await sovereignChainBridgeContract.precalculatedWrapperAddress( networkIDRollup, tokenAddress, tokenName, @@ -807,7 +894,7 @@ describe("PolygonZkEVMBridge Contract", () => { ).to.be.equal(precalculateWrappedErc20); await expect( - polygonZkEVMBridgeContract.claimAsset( + sovereignChainBridgeContract.claimAsset( proofLocal, proofRollup, globalIndex, @@ -821,18 +908,18 @@ describe("PolygonZkEVMBridge Contract", () => { metadata ) ) - .to.emit(polygonZkEVMBridgeContract, "ClaimEvent") + .to.emit(sovereignChainBridgeContract, "ClaimEvent") .withArgs(globalIndex, originNetwork, tokenAddress, destinationAddress, amount) - .to.emit(polygonZkEVMBridgeContract, "NewWrappedToken") + .to.emit(sovereignChainBridgeContract, "NewWrappedToken") .withArgs(originNetwork, tokenAddress, precalculateWrappedErc20, metadata) .to.emit(newWrappedToken, "Transfer") .withArgs(ethers.ZeroAddress, destinationAddress, amount); - const newTokenInfo = await polygonZkEVMBridgeContract.wrappedTokenToTokenInfo(precalculateWrappedErc20); + const newTokenInfo = await sovereignChainBridgeContract.wrappedTokenToTokenInfo(precalculateWrappedErc20); // Use precalculatedWrapperAddress and check if matches expect( - await polygonZkEVMBridgeContract.calculateTokenWrapperAddress( + await sovereignChainBridgeContract.calculateTokenWrapperAddress( networkIDRollup, tokenAddress, precalculateWrappedErc20 @@ -841,14 +928,14 @@ describe("PolygonZkEVMBridge Contract", () => { expect(newTokenInfo.originNetwork).to.be.equal(networkIDRollup); expect(newTokenInfo.originTokenAddress).to.be.equal(tokenAddress); - expect(await polygonZkEVMBridgeContract.getTokenWrappedAddress(networkIDRollup, tokenAddress)).to.be.equal( + expect(await sovereignChainBridgeContract.getTokenWrappedAddress(networkIDRollup, tokenAddress)).to.be.equal( precalculateWrappedErc20 ); - expect(await polygonZkEVMBridgeContract.getTokenWrappedAddress(networkIDRollup, tokenAddress)).to.be.equal( + expect(await sovereignChainBridgeContract.getTokenWrappedAddress(networkIDRollup, tokenAddress)).to.be.equal( precalculateWrappedErc20 ); - expect(await polygonZkEVMBridgeContract.tokenInfoToWrappedToken(salt)).to.be.equal(precalculateWrappedErc20); + expect(await sovereignChainBridgeContract.tokenInfoToWrappedToken(salt)).to.be.equal(precalculateWrappedErc20); // Check the wrapper info expect(await newWrappedToken.name()).to.be.equal(tokenName); @@ -857,7 +944,7 @@ describe("PolygonZkEVMBridge Contract", () => { // Can't claim because nullifier await expect( - polygonZkEVMBridgeContract.claimAsset( + sovereignChainBridgeContract.claimAsset( proofLocal, proofRollup, globalIndex, @@ -870,8 +957,8 @@ describe("PolygonZkEVMBridge Contract", () => { amount, metadata ) - ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "AlreadyClaimed"); - expect(true).to.be.equal(await polygonZkEVMBridgeContract.isClaimed(indexLocal, indexRollup + 1)); + ).to.be.revertedWithCustomError(sovereignChainBridgeContract, "AlreadyClaimed"); + expect(true).to.be.equal(await sovereignChainBridgeContract.isClaimed(indexLocal, indexRollup + 1)); expect(await newWrappedToken.totalSupply()).to.be.equal(amount); @@ -884,7 +971,7 @@ describe("PolygonZkEVMBridge Contract", () => { const globalIndex2 = computeGlobalIndex(index2, indexRollup, false); await expect( - polygonZkEVMBridgeContract.claimAsset( + sovereignChainBridgeContract.claimAsset( proof2, proofRollup, globalIndex2, @@ -898,22 +985,22 @@ describe("PolygonZkEVMBridge Contract", () => { metadata ) ) - .to.emit(polygonZkEVMBridgeContract, "ClaimEvent") + .to.emit(sovereignChainBridgeContract, "ClaimEvent") .withArgs(globalIndex2, originNetwork, tokenAddress, destinationAddress, amount) .to.emit(newWrappedToken, "Transfer") .withArgs(ethers.ZeroAddress, destinationAddress, amount); // Burn Tokens - const depositCount = await polygonZkEVMBridgeContract.depositCount(); + const depositCount = await sovereignChainBridgeContract.depositCount(); const wrappedTokenAddress = newWrappedToken.target; const newDestinationNetwork = networkIDRollup; - const rollupExitRoot = await polygonZkEVMGlobalExitRoot.lastRollupExitRoot(); + const rollupExitRoot = await sovereignChainGlobalExitRoot.lastRollupExitRoot(); // create a new deposit - await expect(newWrappedToken.approve(polygonZkEVMBridgeContract.target, amount)) + await expect(newWrappedToken.approve(sovereignChainBridgeContract.target, amount)) .to.emit(newWrappedToken, "Approval") - .withArgs(deployer.address, polygonZkEVMBridgeContract.target, amount); + .withArgs(deployer.address, sovereignChainBridgeContract.target, amount); /* * pre compute root merkle tree in Js @@ -934,7 +1021,7 @@ describe("PolygonZkEVMBridge Contract", () => { amount, metadataHashMainnet ); - const leafValueMainnetSC = await polygonZkEVMBridgeContract.getLeafValue( + const leafValueMainnetSC = await sovereignChainBridgeContract.getLeafValue( LEAF_TYPE_ASSET, originNetwork, originTokenAddress, @@ -952,7 +1039,7 @@ describe("PolygonZkEVMBridge Contract", () => { expect(await newWrappedToken.totalSupply()).to.be.equal(amount * 2n); expect(await newWrappedToken.balanceOf(destinationAddress)).to.be.equal(amount * 2n); await expect( - polygonZkEVMBridgeContract.bridgeAsset( + sovereignChainBridgeContract.bridgeAsset( newDestinationNetwork, destinationAddress, amount, @@ -961,7 +1048,7 @@ describe("PolygonZkEVMBridge Contract", () => { "0x" ) ) - .to.emit(polygonZkEVMBridgeContract, "BridgeEvent") + .to.emit(sovereignChainBridgeContract, "BridgeEvent") .withArgs( LEAF_TYPE_ASSET, originNetwork, @@ -972,17 +1059,15 @@ describe("PolygonZkEVMBridge Contract", () => { metadataMainnet, depositCount ) - .to.emit(polygonZkEVMGlobalExitRoot, "UpdateGlobalExitRoot") - .withArgs(rootJSMainnet, rollupExitRoot) .to.emit(newWrappedToken, "Transfer") .withArgs(deployer.address, ethers.ZeroAddress, amount); expect(await newWrappedToken.totalSupply()).to.be.equal(amount); expect(await newWrappedToken.balanceOf(deployer.address)).to.be.equal(amount); - expect(await newWrappedToken.balanceOf(polygonZkEVMBridgeContract.target)).to.be.equal(0); + expect(await newWrappedToken.balanceOf(sovereignChainBridgeContract.target)).to.be.equal(0); // check merkle root with SC - const rootSCMainnet = await polygonZkEVMBridgeContract.getRoot(); + const rootSCMainnet = await sovereignChainBridgeContract.getRoot(); expect(rootSCMainnet).to.be.equal(rootJSMainnet); // check merkle proof @@ -992,7 +1077,7 @@ describe("PolygonZkEVMBridge Contract", () => { // verify merkle proof expect(verifyMerkleProof(leafValueMainnet, proofMainnet, indexMainnet, rootSCMainnet)).to.be.equal(true); expect( - await polygonZkEVMBridgeContract.verifyMerkleProof( + await sovereignChainBridgeContract.verifyMerkleProof( leafValueMainnet, proofMainnet, indexMainnet, @@ -1001,19 +1086,25 @@ describe("PolygonZkEVMBridge Contract", () => { ).to.be.equal(true); const computedGlobalExitRoot2 = calculateGlobalExitRoot(rootJSMainnet, rollupExitRoot); - expect(computedGlobalExitRoot2).to.be.equal(await polygonZkEVMGlobalExitRoot.getLastGlobalExitRoot()); + // Insert global exit root + expect(await sovereignChainGlobalExitRoot.insertGlobalExitRoot(computedGlobalExitRoot)) + .to.emit(sovereignChainGlobalExitRoot, "InsertGlobalExitRoot") + .withArgs(computedGlobalExitRoot); + + // Check GER has value in mapping + expect(await sovereignChainGlobalExitRoot.globalExitRootMap(computedGlobalExitRoot)).to.not.be.eq(0); }); - it("should claim tokens from Rollup to Mainnet, faling deploy wrapped", async () => { + it("should claim tokens from Rollup to Mainnet, failing deploy wrapped", async () => { const originNetwork = networkIDRollup; const tokenAddress = polTokenContract.target; const amount = ethers.parseEther("10"); - const destinationNetwork = networkIDMainnet; + const destinationNetwork = networkIDRollup2; const destinationAddress = deployer.address; const metadata = ethers.hexlify(ethers.randomBytes(40)); const metadataHash = ethers.solidityPackedKeccak256(["bytes"], [metadata]); - const mainnetExitRoot = await polygonZkEVMGlobalExitRoot.lastMainnetExitRoot(); + const mainnetExitRoot = ethers.ZeroHash; // compute root merkle tree in Js const height = 32; @@ -1041,25 +1132,29 @@ describe("PolygonZkEVMBridge Contract", () => { const rootRollup = merkleTreeRollup.getRoot(); // check only rollup account with update rollup exit root - await expect(polygonZkEVMGlobalExitRoot.updateExitRoot(rootRollup)).to.be.revertedWithCustomError( - polygonZkEVMGlobalExitRoot, + await expect(sovereignChainGlobalExitRoot.updateExitRoot(rootRollup)).to.be.revertedWithCustomError( + sovereignChainGlobalExitRoot, "OnlyAllowedContracts" ); // add rollup Merkle root - await expect(polygonZkEVMGlobalExitRoot.connect(rollupManager).updateExitRoot(rootRollup)) - .to.emit(polygonZkEVMGlobalExitRoot, "UpdateGlobalExitRoot") - .withArgs(mainnetExitRoot, rootRollup); + await ethers.provider.send("hardhat_impersonateAccount", [sovereignChainBridgeContract.target]); + const bridgeMock = await ethers.getSigner(sovereignChainBridgeContract.target as any); + await sovereignChainGlobalExitRoot.connect(bridgeMock).updateExitRoot(rootRollup, {gasPrice: 0}); // check roots - const rollupExitRootSC = await polygonZkEVMGlobalExitRoot.lastRollupExitRoot(); + const rollupExitRootSC = await sovereignChainGlobalExitRoot.lastRollupExitRoot(); expect(rollupExitRootSC).to.be.equal(rootRollup); const computedGlobalExitRoot = calculateGlobalExitRoot(mainnetExitRoot, rollupExitRootSC); - expect(computedGlobalExitRoot).to.be.equal(await polygonZkEVMGlobalExitRoot.getLastGlobalExitRoot()); + // Insert global exit root + expect(await sovereignChainGlobalExitRoot.insertGlobalExitRoot(computedGlobalExitRoot)) + .to.emit(sovereignChainGlobalExitRoot, "InsertGlobalExitRoot") + .withArgs(computedGlobalExitRoot); + // Check GER has value in mapping + expect(await sovereignChainGlobalExitRoot.globalExitRootMap(computedGlobalExitRoot)).to.not.be.eq(0); // check merkle proof - // Merkle proof local const indexLocal = 0; const proofLocal = merkleTreeLocal.getProofTreeByIndex(indexLocal); @@ -1072,27 +1167,27 @@ describe("PolygonZkEVMBridge Contract", () => { expect(verifyMerkleProof(leafValue, proofLocal, indexLocal, rootLocalRollup)).to.be.equal(true); expect(verifyMerkleProof(rootLocalRollup, proofRollup, indexRollup, rootRollup)).to.be.equal(true); expect( - await polygonZkEVMBridgeContract.verifyMerkleProof(rootLocalRollup, proofRollup, indexRollup, rootRollup) + await sovereignChainBridgeContract.verifyMerkleProof(rootLocalRollup, proofRollup, indexRollup, rootRollup) ).to.be.equal(true); const globalIndex = computeGlobalIndex(indexLocal, indexRollup, false); - expect(false).to.be.equal(await polygonZkEVMBridgeContract.isClaimed(indexLocal, indexRollup + 1)); + expect(false).to.be.equal(await sovereignChainBridgeContract.isClaimed(indexLocal, indexRollup + 1)); // claim const tokenWrappedFactory = await ethers.getContractFactory("TokenWrapped"); // create2 parameters const salt = ethers.solidityPackedKeccak256(["uint32", "address"], [networkIDRollup, tokenAddress]); - const minimalBytecodeProxy = await polygonZkEVMBridgeContract.BASE_INIT_BYTECODE_WRAPPED_TOKEN(); + const minimalBytecodeProxy = await sovereignChainBridgeContract.BASE_INIT_BYTECODE_WRAPPED_TOKEN(); const hashInitCode = ethers.solidityPackedKeccak256(["bytes", "bytes"], [minimalBytecodeProxy, metadataToken]); const precalculateWrappedErc20 = await ethers.getCreate2Address( - polygonZkEVMBridgeContract.target as string, + sovereignChainBridgeContract.target as string, salt, hashInitCode ); // Use precalculatedWrapperAddress and check if matches expect( - await polygonZkEVMBridgeContract.precalculatedWrapperAddress( + await sovereignChainBridgeContract.precalculatedWrapperAddress( networkIDRollup, tokenAddress, tokenName, @@ -1102,7 +1197,7 @@ describe("PolygonZkEVMBridge Contract", () => { ).to.be.equal(precalculateWrappedErc20); await expect( - polygonZkEVMBridgeContract.claimAsset( + sovereignChainBridgeContract.claimAsset( proofLocal, proofRollup, globalIndex, @@ -1115,10 +1210,10 @@ describe("PolygonZkEVMBridge Contract", () => { amount, metadata ) - ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "FailedTokenWrappedDeployment"); + ).to.be.revertedWithCustomError(sovereignChainBridgeContract, "FailedTokenWrappedDeployment"); }); - it("should PolygonZkEVMBridge and sync the current root with events", async () => { - const depositCount = await polygonZkEVMBridgeContract.depositCount(); + it("should sovereignChainBridge and sync the current root with events", async () => { + const depositCount = await sovereignChainBridgeContract.depositCount(); const originNetwork = networkIDMainnet; const tokenAddress = ethers.ZeroAddress; // Ether const amount = ethers.parseEther("10"); @@ -1129,7 +1224,7 @@ describe("PolygonZkEVMBridge Contract", () => { // create 3 new deposit await expect( - polygonZkEVMBridgeContract.bridgeAsset( + sovereignChainBridgeContract.bridgeAsset( destinationNetwork, destinationAddress, amount, @@ -1139,7 +1234,7 @@ describe("PolygonZkEVMBridge Contract", () => { {value: amount} ) ) - .to.emit(polygonZkEVMBridgeContract, "BridgeEvent") + .to.emit(sovereignChainBridgeContract, "BridgeEvent") .withArgs( LEAF_TYPE_ASSET, originNetwork, @@ -1152,7 +1247,7 @@ describe("PolygonZkEVMBridge Contract", () => { ); await expect( - polygonZkEVMBridgeContract.bridgeAsset( + sovereignChainBridgeContract.bridgeAsset( destinationNetwork, destinationAddress, amount, @@ -1162,7 +1257,7 @@ describe("PolygonZkEVMBridge Contract", () => { {value: amount} ) ) - .to.emit(polygonZkEVMBridgeContract, "BridgeEvent") + .to.emit(sovereignChainBridgeContract, "BridgeEvent") .withArgs( LEAF_TYPE_ASSET, originNetwork, @@ -1175,7 +1270,7 @@ describe("PolygonZkEVMBridge Contract", () => { ); await expect( - polygonZkEVMBridgeContract.bridgeAsset( + sovereignChainBridgeContract.bridgeAsset( destinationNetwork, destinationAddress, amount, @@ -1185,7 +1280,7 @@ describe("PolygonZkEVMBridge Contract", () => { {value: amount} ) ) - .to.emit(polygonZkEVMBridgeContract, "BridgeEvent") + .to.emit(sovereignChainBridgeContract, "BridgeEvent") .withArgs( LEAF_TYPE_ASSET, originNetwork, @@ -1202,7 +1297,7 @@ describe("PolygonZkEVMBridge Contract", () => { const merkleTree = new MerkleTreeBridge(height); // Get the deposit's events - const filter = polygonZkEVMBridgeContract.filters.BridgeEvent( + const filter = sovereignChainBridgeContract.filters.BridgeEvent( undefined, undefined, undefined, @@ -1212,7 +1307,7 @@ describe("PolygonZkEVMBridge Contract", () => { undefined, undefined ); - const events = await polygonZkEVMBridgeContract.queryFilter(filter, 0, "latest"); + const events = await sovereignChainBridgeContract.queryFilter(filter, 0, "latest"); events.forEach((e) => { const {args} = e; const leafValue = getLeafValue( @@ -1228,7 +1323,7 @@ describe("PolygonZkEVMBridge Contract", () => { }); // Check merkle root with SC - const rootSC = await polygonZkEVMBridgeContract.getRoot(); + const rootSC = await sovereignChainBridgeContract.getRoot(); const rootJS = merkleTree.getRoot(); expect(rootSC).to.be.equal(rootJS); @@ -1236,16 +1331,16 @@ describe("PolygonZkEVMBridge Contract", () => { it("should claim testing all the asserts", async () => { // Add a claim leaf to rollup exit tree - const originNetwork = networkIDMainnet; + const originNetwork = networkIDRollup2; const tokenAddress = polTokenContract.target; const amount = ethers.parseEther("10"); - const destinationNetwork = networkIDMainnet; + const destinationNetwork = networkIDRollup2; const destinationAddress = deployer.address; const metadata = metadataToken; const metadataHash = ethers.solidityPackedKeccak256(["bytes"], [metadata]); - const mainnetExitRoot = await polygonZkEVMGlobalExitRoot.lastMainnetExitRoot(); + const mainnetExitRoot = ethers.ZeroHash; // compute root merkle tree in Js const height = 32; @@ -1270,16 +1365,21 @@ describe("PolygonZkEVMBridge Contract", () => { const rollupRoot = merkleTreeRollup.getRoot(); // add rollup Merkle root - await expect(polygonZkEVMGlobalExitRoot.connect(rollupManager).updateExitRoot(rollupRoot)) - .to.emit(polygonZkEVMGlobalExitRoot, "UpdateGlobalExitRoot") - .withArgs(mainnetExitRoot, rollupRoot); - + await ethers.provider.send("hardhat_impersonateAccount", [sovereignChainBridgeContract.target]); + const bridgeMock = await ethers.getSigner(sovereignChainBridgeContract.target as any); + await sovereignChainGlobalExitRoot.connect(bridgeMock).updateExitRoot(rollupRoot, {gasPrice: 0}); // check roots - const rollupExitRootSC = await polygonZkEVMGlobalExitRoot.lastRollupExitRoot(); + const rollupExitRootSC = await sovereignChainGlobalExitRoot.lastRollupExitRoot(); expect(rollupExitRootSC).to.be.equal(rollupRoot); const computedGlobalExitRoot = calculateGlobalExitRoot(mainnetExitRoot, rollupExitRootSC); - expect(computedGlobalExitRoot).to.be.equal(await polygonZkEVMGlobalExitRoot.getLastGlobalExitRoot()); + // Insert global exit root + expect(await sovereignChainGlobalExitRoot.insertGlobalExitRoot(computedGlobalExitRoot)) + .to.emit(sovereignChainGlobalExitRoot, "InsertGlobalExitRoot") + .withArgs(computedGlobalExitRoot); + + // Check GER has value in mapping + expect(await sovereignChainGlobalExitRoot.globalExitRootMap(computedGlobalExitRoot)).to.not.be.eq(0); // check merkle proof const index = 0; @@ -1289,13 +1389,13 @@ describe("PolygonZkEVMBridge Contract", () => { // verify merkle proof expect(verifyMerkleProof(leafValue, proofLocal, index, rootJSRollup)).to.be.equal(true); expect( - await polygonZkEVMBridgeContract.verifyMerkleProof(leafValue, proofLocal, index, rootJSRollup) + await sovereignChainBridgeContract.verifyMerkleProof(leafValue, proofLocal, index, rootJSRollup) ).to.be.equal(true); const globalIndex = computeGlobalIndex(index, index, false); // Can't claim without tokens await expect( - polygonZkEVMBridgeContract.claimAsset( + sovereignChainBridgeContract.claimAsset( proofLocal, proofRollup, globalIndex, @@ -1311,30 +1411,13 @@ describe("PolygonZkEVMBridge Contract", () => { ).to.be.revertedWith("ERC20: transfer amount exceeds balance"); // transfer tokens, then claim - await expect(polTokenContract.transfer(polygonZkEVMBridgeContract.target, amount)) + await expect(polTokenContract.transfer(sovereignChainBridgeContract.target, amount)) .to.emit(polTokenContract, "Transfer") - .withArgs(deployer.address, polygonZkEVMBridgeContract.target, amount); - - // Check Destination network does not match assert - // await expect( - // polygonZkEVMBridgeContract.claimAsset( - // proofLocal, - // proofRollup, - // globalIndex, - // mainnetExitRoot, - // rollupExitRootSC, - // originNetwork, - // tokenAddress, - // destinationNetwork, - // destinationAddress, - // amount, - // metadata - // ) - // ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "DestinationNetworkInvalid"); + .withArgs(deployer.address, sovereignChainBridgeContract.target, amount); // Check GlobalExitRoot invalid assert await expect( - polygonZkEVMBridgeContract.claimAsset( + sovereignChainBridgeContract.claimAsset( proofLocal, proofRollup, globalIndex, @@ -1347,11 +1430,11 @@ describe("PolygonZkEVMBridge Contract", () => { amount, metadata ) - ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "GlobalExitRootInvalid"); + ).to.be.revertedWithCustomError(sovereignChainBridgeContract, "GlobalExitRootInvalid"); // Check Invalid smt proof assert await expect( - polygonZkEVMBridgeContract.claimAsset( + sovereignChainBridgeContract.claimAsset( proofLocal, proofRollup, globalIndex + 1n, @@ -1364,10 +1447,10 @@ describe("PolygonZkEVMBridge Contract", () => { amount, metadata ) - ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "InvalidSmtProof"); + ).to.be.revertedWithCustomError(sovereignChainBridgeContract, "InvalidSmtProof"); await expect( - polygonZkEVMBridgeContract.claimAsset( + sovereignChainBridgeContract.claimAsset( proofLocal, proofRollup, globalIndex, @@ -1381,14 +1464,14 @@ describe("PolygonZkEVMBridge Contract", () => { metadata ) ) - .to.emit(polygonZkEVMBridgeContract, "ClaimEvent") + .to.emit(sovereignChainBridgeContract, "ClaimEvent") .withArgs(index, originNetwork, tokenAddress, destinationAddress, amount) .to.emit(polTokenContract, "Transfer") - .withArgs(polygonZkEVMBridgeContract.target, deployer.address, amount); + .withArgs(sovereignChainBridgeContract.target, deployer.address, amount); // Check Already claimed_claim await expect( - polygonZkEVMBridgeContract.claimAsset( + sovereignChainBridgeContract.claimAsset( proofLocal, proofRollup, globalIndex, @@ -1401,7 +1484,7 @@ describe("PolygonZkEVMBridge Contract", () => { amount, metadata ) - ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "AlreadyClaimed"); + ).to.be.revertedWithCustomError(sovereignChainBridgeContract, "AlreadyClaimed"); }); it("should claim ether", async () => { @@ -1409,13 +1492,13 @@ describe("PolygonZkEVMBridge Contract", () => { const originNetwork = networkIDMainnet; const tokenAddress = ethers.ZeroAddress; // ether const amount = ethers.parseEther("10"); - const destinationNetwork = networkIDMainnet; + const destinationNetwork = networkIDRollup2; const destinationAddress = deployer.address; const metadata = "0x"; // since is ether does not have metadata const metadataHash = ethers.solidityPackedKeccak256(["bytes"], [metadata]); - const mainnetExitRoot = await polygonZkEVMGlobalExitRoot.lastMainnetExitRoot(); + const mainnetExitRoot = ethers.ZeroHash; // compute root merkle tree in Js const height = 32; @@ -1438,16 +1521,22 @@ describe("PolygonZkEVMBridge Contract", () => { const rollupRoot = merkleTreeRollup.getRoot(); // add rollup Merkle root - await expect(polygonZkEVMGlobalExitRoot.connect(rollupManager).updateExitRoot(rollupRoot)) - .to.emit(polygonZkEVMGlobalExitRoot, "UpdateGlobalExitRoot") - .withArgs(mainnetExitRoot, rollupRoot); + await ethers.provider.send("hardhat_impersonateAccount", [sovereignChainBridgeContract.target]); + const bridgeMock = await ethers.getSigner(sovereignChainBridgeContract.target as any); + await sovereignChainGlobalExitRoot.connect(bridgeMock).updateExitRoot(rollupRoot, {gasPrice: 0}); // check roots - const rollupExitRootSC = await polygonZkEVMGlobalExitRoot.lastRollupExitRoot(); + const rollupExitRootSC = await sovereignChainGlobalExitRoot.lastRollupExitRoot(); expect(rollupExitRootSC).to.be.equal(rollupRoot); const computedGlobalExitRoot = calculateGlobalExitRoot(mainnetExitRoot, rollupExitRootSC); - expect(computedGlobalExitRoot).to.be.equal(await polygonZkEVMGlobalExitRoot.getLastGlobalExitRoot()); + // Insert global exit root + expect(await sovereignChainGlobalExitRoot.insertGlobalExitRoot(computedGlobalExitRoot)) + .to.emit(sovereignChainGlobalExitRoot, "InsertGlobalExitRoot") + .withArgs(computedGlobalExitRoot); + + // Check GER has value in mapping + expect(await sovereignChainGlobalExitRoot.globalExitRootMap(computedGlobalExitRoot)).to.not.be.eq(0); // check merkle proof const index = 0; @@ -1458,7 +1547,7 @@ describe("PolygonZkEVMBridge Contract", () => { // verify merkle proof expect(verifyMerkleProof(leafValue, proofLocal, index, rootJSRollup)).to.be.equal(true); expect( - await polygonZkEVMBridgeContract.verifyMerkleProof(leafValue, proofLocal, index, rootJSRollup) + await sovereignChainBridgeContract.verifyMerkleProof(leafValue, proofLocal, index, rootJSRollup) ).to.be.equal(true); /* @@ -1466,7 +1555,7 @@ describe("PolygonZkEVMBridge Contract", () => { * Can't claim without ether */ await expect( - polygonZkEVMBridgeContract.claimAsset( + sovereignChainBridgeContract.claimAsset( proofLocal, proofRollup, globalIndex, @@ -1479,29 +1568,13 @@ describe("PolygonZkEVMBridge Contract", () => { amount, metadata ) - ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "EtherTransferFailed"); + ).to.be.revertedWithCustomError(sovereignChainBridgeContract, "EtherTransferFailed"); const balanceDeployer = await ethers.provider.getBalance(deployer.address); - /* - * Create a deposit to add ether to the PolygonZkEVMBridge - * Check deposit amount ether asserts - */ - // await expect( - // polygonZkEVMBridgeContract.bridgeAsset( - // networkIDRollup, - // destinationAddress, - // amount, - // tokenAddress, - // true, - // "0x", - // {value: ethers.parseEther("100")} - // ) - // ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "AmountDoesNotMatchMsgValue"); - // Check mainnet destination assert await expect( - polygonZkEVMBridgeContract.bridgeAsset( - networkIDMainnet, + sovereignChainBridgeContract.bridgeAsset( + networkIDRollup2, destinationAddress, amount, tokenAddress, @@ -1509,11 +1582,11 @@ describe("PolygonZkEVMBridge Contract", () => { "0x", {value: amount} ) - ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "DestinationNetworkInvalid"); + ).to.be.revertedWithCustomError(sovereignChainBridgeContract, "DestinationNetworkInvalid"); - // This is used just to pay ether to the PolygonZkEVMBridge smart contract and be able to claim it afterwards. + // This is used just to pay ether to the SovereignChain smart contract and be able to claim it afterwards. expect( - await polygonZkEVMBridgeContract.bridgeAsset( + await sovereignChainBridgeContract.bridgeAsset( networkIDRollup, destinationAddress, amount, @@ -1525,11 +1598,11 @@ describe("PolygonZkEVMBridge Contract", () => { ); // Check balances before claim - expect(await ethers.provider.getBalance(polygonZkEVMBridgeContract.target)).to.be.equal(amount); + expect(await ethers.provider.getBalance(sovereignChainBridgeContract.target)).to.be.equal(amount); expect(await ethers.provider.getBalance(deployer.address)).to.be.lte(balanceDeployer - amount); await expect( - polygonZkEVMBridgeContract.claimAsset( + sovereignChainBridgeContract.claimAsset( proofLocal, proofRollup, globalIndex, @@ -1543,16 +1616,18 @@ describe("PolygonZkEVMBridge Contract", () => { metadata ) ) - .to.emit(polygonZkEVMBridgeContract, "ClaimEvent") + .to.emit(sovereignChainBridgeContract, "ClaimEvent") .withArgs(index, originNetwork, tokenAddress, destinationAddress, amount); // Check balances after claim - expect(await ethers.provider.getBalance(polygonZkEVMBridgeContract.target)).to.be.equal(ethers.parseEther("0")); + expect(await ethers.provider.getBalance(sovereignChainBridgeContract.target)).to.be.equal( + ethers.parseEther("0") + ); expect(await ethers.provider.getBalance(deployer.address)).to.be.lte(balanceDeployer); // Can't claim because nullifier await expect( - polygonZkEVMBridgeContract.claimAsset( + sovereignChainBridgeContract.claimAsset( proofLocal, proofRollup, globalIndex, @@ -1565,7 +1640,7 @@ describe("PolygonZkEVMBridge Contract", () => { amount, metadata ) - ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "AlreadyClaimed"); + ).to.be.revertedWithCustomError(sovereignChainBridgeContract, "AlreadyClaimed"); }); it("should claim message", async () => { @@ -1573,13 +1648,13 @@ describe("PolygonZkEVMBridge Contract", () => { const originNetwork = networkIDMainnet; const tokenAddress = ethers.ZeroAddress; // ether const amount = ethers.parseEther("10"); - const destinationNetwork = networkIDMainnet; + const destinationNetwork = networkIDRollup2; const destinationAddress = deployer.address; const metadata = "0x176923791298713271763697869132"; // since is ether does not have metadata const metadataHash = ethers.solidityPackedKeccak256(["bytes"], [metadata]); - const mainnetExitRoot = await polygonZkEVMGlobalExitRoot.lastMainnetExitRoot(); + const mainnetExitRoot = ethers.ZeroHash; // compute root merkle tree in Js const height = 32; @@ -1602,17 +1677,22 @@ describe("PolygonZkEVMBridge Contract", () => { const rollupRoot = merkleTreeRollup.getRoot(); // add rollup Merkle root - await expect(polygonZkEVMGlobalExitRoot.connect(rollupManager).updateExitRoot(rollupRoot)) - .to.emit(polygonZkEVMGlobalExitRoot, "UpdateGlobalExitRoot") - .withArgs(mainnetExitRoot, rollupRoot); + await ethers.provider.send("hardhat_impersonateAccount", [sovereignChainBridgeContract.target]); + const bridgeMock = await ethers.getSigner(sovereignChainBridgeContract.target as any); + await sovereignChainGlobalExitRoot.connect(bridgeMock).updateExitRoot(rollupRoot, {gasPrice: 0}); // check roots - const rollupExitRootSC = await polygonZkEVMGlobalExitRoot.lastRollupExitRoot(); + const rollupExitRootSC = await sovereignChainGlobalExitRoot.lastRollupExitRoot(); expect(rollupExitRootSC).to.be.equal(rollupRoot); const computedGlobalExitRoot = calculateGlobalExitRoot(mainnetExitRoot, rollupExitRootSC); - expect(computedGlobalExitRoot).to.be.equal(await polygonZkEVMGlobalExitRoot.getLastGlobalExitRoot()); + // Insert global exit root + expect(await sovereignChainGlobalExitRoot.insertGlobalExitRoot(computedGlobalExitRoot)) + .to.emit(sovereignChainGlobalExitRoot, "InsertGlobalExitRoot") + .withArgs(computedGlobalExitRoot); + // Check GER has value in mapping + expect(await sovereignChainGlobalExitRoot.globalExitRootMap(computedGlobalExitRoot)).to.not.be.eq(0); // check merkle proof const index = 0; const proofLocal = merkleTree.getProofTreeByIndex(0); @@ -1622,7 +1702,7 @@ describe("PolygonZkEVMBridge Contract", () => { // verify merkle proof expect(verifyMerkleProof(leafValue, proofLocal, index, rootJSRollup)).to.be.equal(true); expect( - await polygonZkEVMBridgeContract.verifyMerkleProof(leafValue, proofLocal, index, rootJSRollup) + await sovereignChainBridgeContract.verifyMerkleProof(leafValue, proofLocal, index, rootJSRollup) ).to.be.equal(true); /* @@ -1630,7 +1710,7 @@ describe("PolygonZkEVMBridge Contract", () => { * Can't claim a message as an assets */ await expect( - polygonZkEVMBridgeContract.claimAsset( + sovereignChainBridgeContract.claimAsset( proofLocal, proofRollup, globalIndex, @@ -1643,14 +1723,14 @@ describe("PolygonZkEVMBridge Contract", () => { amount, metadata ) - ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "InvalidSmtProof"); + ).to.be.revertedWithCustomError(sovereignChainBridgeContract, "InvalidSmtProof"); /* * claim * Can't claim invalid destination network */ await expect( - polygonZkEVMBridgeContract.claimMessage( + sovereignChainBridgeContract.claimMessage( proofLocal, proofRollup, globalIndex, @@ -1663,14 +1743,14 @@ describe("PolygonZkEVMBridge Contract", () => { amount, metadata ) - ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "DestinationNetworkInvalid"); + ).to.be.revertedWithCustomError(sovereignChainBridgeContract, "DestinationNetworkInvalid"); /* * claim * Can't claim without ether */ await expect( - polygonZkEVMBridgeContract.claimMessage( + sovereignChainBridgeContract.claimMessage( proofLocal, proofRollup, globalIndex, @@ -1683,10 +1763,10 @@ describe("PolygonZkEVMBridge Contract", () => { amount, metadata ) - ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "MessageFailed"); + ).to.be.revertedWithCustomError(sovereignChainBridgeContract, "MessageFailed"); await expect( - polygonZkEVMBridgeContract.claimAsset( + sovereignChainBridgeContract.claimAsset( proofLocal, proofRollup, globalIndex, @@ -1699,15 +1779,15 @@ describe("PolygonZkEVMBridge Contract", () => { amount, metadata ) - ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "DestinationNetworkInvalid"); + ).to.be.revertedWithCustomError(sovereignChainBridgeContract, "DestinationNetworkInvalid"); const balanceDeployer = await ethers.provider.getBalance(deployer.address); /* - * Create a deposit to add ether to the PolygonZkEVMBridge + * Create a deposit to add ether to the SovereignChainBridge * Check deposit amount ether asserts */ await expect( - polygonZkEVMBridgeContract.bridgeAsset( + sovereignChainBridgeContract.bridgeAsset( networkIDRollup, destinationAddress, amount, @@ -1716,12 +1796,12 @@ describe("PolygonZkEVMBridge Contract", () => { "0x", {value: ethers.parseEther("100")} ) - ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "AmountDoesNotMatchMsgValue"); + ).to.be.revertedWithCustomError(sovereignChainBridgeContract, "AmountDoesNotMatchMsgValue"); // Check mainnet destination assert await expect( - polygonZkEVMBridgeContract.bridgeAsset( - networkIDMainnet, + sovereignChainBridgeContract.bridgeAsset( + networkIDRollup2, destinationAddress, amount, tokenAddress, @@ -1729,11 +1809,11 @@ describe("PolygonZkEVMBridge Contract", () => { "0x", {value: amount} ) - ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "DestinationNetworkInvalid"); + ).to.be.revertedWithCustomError(sovereignChainBridgeContract, "DestinationNetworkInvalid"); - // This is used just to pay ether to the PolygonZkEVMBridge smart contract and be able to claim it afterwards. + // This is used just to pay ether to the SovereignChainBridge smart contract and be able to claim it afterwards. expect( - await polygonZkEVMBridgeContract.bridgeAsset( + await sovereignChainBridgeContract.bridgeAsset( networkIDRollup, destinationAddress, amount, @@ -1745,12 +1825,12 @@ describe("PolygonZkEVMBridge Contract", () => { ); // Check balances before claim - expect(await ethers.provider.getBalance(polygonZkEVMBridgeContract.target)).to.be.equal(amount); + expect(await ethers.provider.getBalance(sovereignChainBridgeContract.target)).to.be.equal(amount); expect(await ethers.provider.getBalance(deployer.address)).to.be.lte(balanceDeployer - amount); // Check mainnet destination assert await expect( - polygonZkEVMBridgeContract.claimAsset( + sovereignChainBridgeContract.claimAsset( proofLocal, proofRollup, globalIndex, @@ -1763,10 +1843,10 @@ describe("PolygonZkEVMBridge Contract", () => { amount, metadata ) - ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "InvalidSmtProof"); + ).to.be.revertedWithCustomError(sovereignChainBridgeContract, "InvalidSmtProof"); await expect( - polygonZkEVMBridgeContract.claimMessage( + sovereignChainBridgeContract.claimMessage( proofLocal, proofRollup, globalIndex, @@ -1780,16 +1860,18 @@ describe("PolygonZkEVMBridge Contract", () => { metadata ) ) - .to.emit(polygonZkEVMBridgeContract, "ClaimEvent") + .to.emit(sovereignChainBridgeContract, "ClaimEvent") .withArgs(index, originNetwork, tokenAddress, destinationAddress, amount); // Check balances after claim - expect(await ethers.provider.getBalance(polygonZkEVMBridgeContract.target)).to.be.equal(ethers.parseEther("0")); + expect(await ethers.provider.getBalance(sovereignChainBridgeContract.target)).to.be.equal( + ethers.parseEther("0") + ); expect(await ethers.provider.getBalance(deployer.address)).to.be.lte(balanceDeployer); // Can't claim because nullifier await expect( - polygonZkEVMBridgeContract.claimMessage( + sovereignChainBridgeContract.claimMessage( proofLocal, proofRollup, globalIndex, @@ -1802,17 +1884,17 @@ describe("PolygonZkEVMBridge Contract", () => { amount, metadata ) - ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "AlreadyClaimed"); + ).to.be.revertedWithCustomError(sovereignChainBridgeContract, "AlreadyClaimed"); }); it("should test emergency state", async () => { - await expect(polygonZkEVMBridgeContract.activateEmergencyState()).to.be.revertedWithCustomError( - polygonZkEVMBridgeContract, + await expect(sovereignChainBridgeContract.activateEmergencyState()).to.be.revertedWithCustomError( + sovereignChainBridgeContract, "OnlyRollupManager" ); - await expect(polygonZkEVMBridgeContract.connect(rollupManager).activateEmergencyState()).to.emit( - polygonZkEVMBridgeContract, + await expect(sovereignChainBridgeContract.connect(rollupManager).activateEmergencyState()).to.emit( + sovereignChainBridgeContract, "EmergencyStateActivated" ); @@ -1824,7 +1906,7 @@ describe("PolygonZkEVMBridge Contract", () => { const metadata = metadataToken; await expect( - polygonZkEVMBridgeContract.bridgeAsset( + sovereignChainBridgeContract.bridgeAsset( destinationNetwork, destinationAddress, amount, @@ -1832,19 +1914,19 @@ describe("PolygonZkEVMBridge Contract", () => { true, "0x" ) - ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "OnlyNotEmergencyState"); + ).to.be.revertedWithCustomError(sovereignChainBridgeContract, "OnlyNotEmergencyState"); await expect( - polygonZkEVMBridgeContract.bridgeMessage(destinationNetwork, destinationAddress, true, "0x") - ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "OnlyNotEmergencyState"); + sovereignChainBridgeContract.bridgeMessage(destinationNetwork, destinationAddress, true, "0x") + ).to.be.revertedWithCustomError(sovereignChainBridgeContract, "OnlyNotEmergencyState"); await expect( - polygonZkEVMBridgeContract.bridgeMessageWETH(destinationNetwork, destinationAddress, amount, true, "0x") - ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "OnlyNotEmergencyState"); + sovereignChainBridgeContract.bridgeMessageWETH(destinationNetwork, destinationAddress, amount, true, "0x") + ).to.be.revertedWithCustomError(sovereignChainBridgeContract, "OnlyNotEmergencyState"); const mockMerkleProof = new Array(32).fill(ethers.ZeroHash) as any; await expect( - polygonZkEVMBridgeContract.claimAsset( + sovereignChainBridgeContract.claimAsset( mockMerkleProof, mockMerkleProof, ethers.ZeroHash, @@ -1857,10 +1939,10 @@ describe("PolygonZkEVMBridge Contract", () => { amount, metadata ) - ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "OnlyNotEmergencyState"); + ).to.be.revertedWithCustomError(sovereignChainBridgeContract, "OnlyNotEmergencyState"); await expect( - polygonZkEVMBridgeContract.claimMessage( + sovereignChainBridgeContract.claimMessage( mockMerkleProof, mockMerkleProof, ethers.ZeroHash, @@ -1873,6 +1955,6 @@ describe("PolygonZkEVMBridge Contract", () => { amount, metadata ) - ).to.be.revertedWithCustomError(polygonZkEVMBridgeContract, "OnlyNotEmergencyState"); + ).to.be.revertedWithCustomError(sovereignChainBridgeContract, "OnlyNotEmergencyState"); }); });