From 3c10a329a02a3f3ad98a2a9f7c3da3ed5e841e39 Mon Sep 17 00:00:00 2001 From: skosito Date: Mon, 15 Jul 2024 17:40:32 +0200 Subject: [PATCH] migrate upgrade test --- contracts/prototypes/evm/ERC20CustodyNew.sol | 2 +- contracts/prototypes/evm/GatewayEVM.sol | 2 +- .../prototypes/evm/GatewayEVMUpgradeTest.sol | 1 + contracts/prototypes/evm/ReceiverEVM.sol | 2 +- contracts/prototypes/evm/TestERC20.sol | 2 +- contracts/prototypes/evm/interfaces.sol | 2 +- contracts/prototypes/test/GatewayEVM.t.sol | 11 ++- .../prototypes/test/GatewayEVMUpgrade.t.sol | 86 +++++++++++++++++++ foundry.toml | 7 +- package.json | 2 +- remappings.txt | 1 + test/prototypes/GatewayEVMUpgrade.spec.ts | 73 ---------------- 12 files changed, 108 insertions(+), 83 deletions(-) create mode 100644 contracts/prototypes/test/GatewayEVMUpgrade.t.sol delete mode 100644 test/prototypes/GatewayEVMUpgrade.spec.ts diff --git a/contracts/prototypes/evm/ERC20CustodyNew.sol b/contracts/prototypes/evm/ERC20CustodyNew.sol index 89a1c597..0b0ec3f2 100644 --- a/contracts/prototypes/evm/ERC20CustodyNew.sol +++ b/contracts/prototypes/evm/ERC20CustodyNew.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.7; +pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "./interfaces.sol"; diff --git a/contracts/prototypes/evm/GatewayEVM.sol b/contracts/prototypes/evm/GatewayEVM.sol index 676b23ef..7c22082e 100644 --- a/contracts/prototypes/evm/GatewayEVM.sol +++ b/contracts/prototypes/evm/GatewayEVM.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.7; +pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; diff --git a/contracts/prototypes/evm/GatewayEVMUpgradeTest.sol b/contracts/prototypes/evm/GatewayEVMUpgradeTest.sol index 00d3342f..13307c0c 100644 --- a/contracts/prototypes/evm/GatewayEVMUpgradeTest.sol +++ b/contracts/prototypes/evm/GatewayEVMUpgradeTest.sol @@ -11,6 +11,7 @@ import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; // NOTE: Purpose of this contract is to test upgrade process, the only difference should be name of Executed event // The Gateway contract is the endpoint to call smart contracts on external chains // The contract doesn't hold any funds and should never have active allowances +/// @custom:oz-upgrades-from GatewayEVM contract GatewayEVMUpgradeTest is Initializable, OwnableUpgradeable, UUPSUpgradeable { using SafeERC20 for IERC20; diff --git a/contracts/prototypes/evm/ReceiverEVM.sol b/contracts/prototypes/evm/ReceiverEVM.sol index 1ac1ad26..c13597b5 100644 --- a/contracts/prototypes/evm/ReceiverEVM.sol +++ b/contracts/prototypes/evm/ReceiverEVM.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.7; +pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; diff --git a/contracts/prototypes/evm/TestERC20.sol b/contracts/prototypes/evm/TestERC20.sol index 6a9859c3..7ffb1988 100644 --- a/contracts/prototypes/evm/TestERC20.sol +++ b/contracts/prototypes/evm/TestERC20.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.7; +pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; diff --git a/contracts/prototypes/evm/interfaces.sol b/contracts/prototypes/evm/interfaces.sol index d170da79..9f89c877 100644 --- a/contracts/prototypes/evm/interfaces.sol +++ b/contracts/prototypes/evm/interfaces.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.7; +pragma solidity ^0.8.0; interface IGatewayEVMEvents { event Executed(address indexed destination, uint256 value, bytes data); diff --git a/contracts/prototypes/test/GatewayEVM.t.sol b/contracts/prototypes/test/GatewayEVM.t.sol index 0abd0512..69228fb9 100644 --- a/contracts/prototypes/test/GatewayEVM.t.sol +++ b/contracts/prototypes/test/GatewayEVM.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.7; +pragma solidity ^0.8.0; import "forge-std/Test.sol"; import "forge-std/Vm.sol"; @@ -10,7 +10,9 @@ import "contracts/prototypes/evm/ERC20CustodyNew.sol"; import "contracts/prototypes/evm/TestERC20.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; import "../evm/interfaces.sol"; +import {Upgrades} from "openzeppelin-foundry-upgrades/LegacyUpgrades.sol"; contract GatewayEVMTest is Test, IGatewayEVMErrors, IGatewayEVMEvents, IReceiverEVMEvents { using SafeERC20 for IERC20; @@ -157,10 +159,13 @@ contract GatewayEVMInboundTest is Test, IGatewayEVMErrors, IGatewayEVMEvents, IR tssAddress = address(0x5678); token = new TestERC20("test", "TTK"); - gateway = new GatewayEVM(); + address proxy = address(new ERC1967Proxy( + address(new GatewayEVM()), + abi.encodeWithSelector(GatewayEVM.initialize.selector, (tssAddress)) + )); + gateway = GatewayEVM(proxy); custody = new ERC20CustodyNew(address(gateway)); - gateway.initialize(tssAddress); gateway.setCustody(address(custody)); // Mint initial supply to the owner diff --git a/contracts/prototypes/test/GatewayEVMUpgrade.t.sol b/contracts/prototypes/test/GatewayEVMUpgrade.t.sol new file mode 100644 index 00000000..0aeb784b --- /dev/null +++ b/contracts/prototypes/test/GatewayEVMUpgrade.t.sol @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "forge-std/Test.sol"; +import "forge-std/Vm.sol"; + +import "contracts/prototypes/evm/GatewayEVM.sol"; +import "contracts/prototypes/evm/GatewayEVMUpgradeTest.sol"; +import "contracts/prototypes/evm/ReceiverEVM.sol"; +import "contracts/prototypes/evm/ERC20CustodyNew.sol"; +import "contracts/prototypes/evm/TestERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; +import "../evm/interfaces.sol"; +import {Upgrades} from "openzeppelin-foundry-upgrades/LegacyUpgrades.sol"; + +contract GatewayEVMUUPSUpgradeTest is Test, IGatewayEVMErrors, IGatewayEVMEvents, IReceiverEVMEvents { + using SafeERC20 for IERC20; + event ExecutedV2(address indexed destination, uint256 value, bytes data); + + address proxy; + GatewayEVM gateway; + ReceiverEVM receiver; + ERC20CustodyNew custody; + TestERC20 token; + address owner; + address destination; + address tssAddress; + + function setUp() public { + owner = address(this); + destination = address(0x1234); + tssAddress = address(0x5678); + + token = new TestERC20("test", "TTK"); + + proxy = address(new ERC1967Proxy( + address(new GatewayEVM()), + abi.encodeWithSelector(GatewayEVM.initialize.selector, (tssAddress)) + )); + gateway = GatewayEVM(proxy); + + custody = new ERC20CustodyNew(address(gateway)); + receiver = new ReceiverEVM(); + + gateway.setCustody(address(custody)); + + // Mint initial supply to the owner + token.mint(owner, 1000000); + + // Transfer some tokens to the custody contract + token.transfer(address(custody), 500000); + } + + function testUpgradeAndForwardCallToReceivePayable() public { + address custodyBeforeUpgrade = gateway.custody(); + address tssBeforeUpgrade = gateway.tssAddress(); + + string memory str = "Hello, Foundry!"; + uint256 num = 42; + bool flag = true; + uint256 value = 1 ether; + + vm.prank(owner); + Upgrades.upgradeProxy( + proxy, + "GatewayEVMUpgradeTest.sol", + "", + owner + ); + + bytes memory data = abi.encodeWithSignature("receivePayable(string,uint256,bool)", str, num, flag); + GatewayEVMUpgradeTest gatewayUpgradeTest = GatewayEVMUpgradeTest(proxy); + + vm.expectCall(address(receiver), value, data); + vm.expectEmit(true, true, true, true, address(receiver)); + emit ReceivedPayable(address(gateway), value, str, num, flag); + vm.expectEmit(true, true, true, true, address(gateway)); + emit ExecutedV2(address(receiver), value, data); + gateway.execute{value: value}(address(receiver), data); + + assertEq(custodyBeforeUpgrade, gateway.custody()); + assertEq(tssBeforeUpgrade, gateway.tssAddress()); + } +} \ No newline at end of file diff --git a/foundry.toml b/foundry.toml index 7c103896..616c9888 100644 --- a/foundry.toml +++ b/foundry.toml @@ -6,4 +6,9 @@ test = 'test' cache_path = 'cache_forge' no-match-contract = '.*EchidnaTest$' optimizer = true -optimizer_runs = 10_000 \ No newline at end of file +optimizer_runs = 10_000 +ffi = true +ast = true +build_info = true +extra_output = ["storageLayout"] +fs_permissions = [{ access = "read", path = "out"}] \ No newline at end of file diff --git a/package.json b/package.json index 26012fa4..841d1d0e 100644 --- a/package.json +++ b/package.json @@ -89,7 +89,7 @@ "localnet": "concurrently --names \"NODE,WORKER\" --prefix-colors \"blue.bold,green.bold\" \"npx hardhat node\" \"wait-on tcp:8545 && yarn worker\"", "prepublishOnly": "yarn build", "test": "npx hardhat test", - "test:forge": "forge test -vvv", + "test:forge": "forge clean && forge test -vvv", "test:prototypes": "yarn compile && npx hardhat test test/prototypes/*", "tsc:watch": "npx tsc --watch", "worker": "npx hardhat run scripts/worker.ts --network localhost" diff --git a/remappings.txt b/remappings.txt index b97ee9cf..8b720f8c 100644 --- a/remappings.txt +++ b/remappings.txt @@ -1,2 +1,3 @@ @openzeppelin/=node_modules/@openzeppelin/ +@openzeppelin/contracts-upgradeable/=node_modules/@openzeppelin/contracts-upgradeable/ forge-std/=lib/forge-std/src/ \ No newline at end of file diff --git a/test/prototypes/GatewayEVMUpgrade.spec.ts b/test/prototypes/GatewayEVMUpgrade.spec.ts deleted file mode 100644 index 8e663ea1..00000000 --- a/test/prototypes/GatewayEVMUpgrade.spec.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { expect } from "chai"; -import { Contract } from "ethers"; -import { ethers, upgrades } from "hardhat"; - -describe("GatewayEVM upgrade", function () { - let receiver: Contract; - let gateway: Contract; - let token: Contract; - let custody: Contract; - let owner: any, destination: any, randomSigner: any, tssAddress: any; - - beforeEach(async function () { - const TestERC20 = await ethers.getContractFactory("TestERC20"); - const Receiver = await ethers.getContractFactory("ReceiverEVM"); - const Gateway = await ethers.getContractFactory("GatewayEVM"); - const Custody = await ethers.getContractFactory("ERC20CustodyNew"); - [owner, destination, randomSigner, tssAddress] = await ethers.getSigners(); - - // Deploy the contracts - token = await TestERC20.deploy("Test Token", "TTK"); - receiver = await Receiver.deploy(); - gateway = await upgrades.deployProxy(Gateway, [tssAddress.address], { - initializer: "initialize", - kind: "uups", - }); - custody = await Custody.deploy(gateway.address); - - gateway.setCustody(custody.address); - - // Mint initial supply to the owner - await token.mint(owner.address, ethers.utils.parseEther("1000")); - - // Transfer some tokens to the custody contract - await token.transfer(custody.address, ethers.utils.parseEther("500")); - }); - - it("should upgrade and forward call to Receiver's receiveA function", async function () { - const custodyBeforeUpgrade = await gateway.custody(); - const tssAddressBeforeUpgrade = await gateway.tssAddress(); - - // Upgrade Gateway contract - // Fail to upgrade if not using owner account - let GatewayUpgradeTest = await ethers.getContractFactory("GatewayEVMUpgradeTest", randomSigner); - await expect(upgrades.upgradeProxy(gateway.address, GatewayUpgradeTest)).to.be.revertedWith( - "Ownable: caller is not the owner" - ); - - // Upgrade with owner account - GatewayUpgradeTest = await ethers.getContractFactory("GatewayEVMUpgradeTest", owner); - - const gatewayUpgradeTest = await upgrades.upgradeProxy(gateway.address, GatewayUpgradeTest); - - // Forward call - const str = "Hello, Hardhat!"; - const num = 42; - const flag = true; - const value = ethers.utils.parseEther("1.0"); - - // Encode the function call data - const data = receiver.interface.encodeFunctionData("receivePayable", [str, num, flag]); - - // Call execute on the GatewayV2 contract - const tx = await gatewayUpgradeTest.execute(receiver.address, data, { value: value }); - - // Listen for the event - await expect(tx).to.emit(gatewayUpgradeTest, "ExecutedV2").withArgs(receiver.address, value, data); - await expect(tx).to.emit(receiver, "ReceivedPayable").withArgs(gatewayUpgradeTest.address, value, str, num, flag); - - // Check that storage is not changed - expect(await gatewayUpgradeTest.custody()).to.equal(custodyBeforeUpgrade); - expect(await gatewayUpgradeTest.tssAddress()).to.equal(tssAddressBeforeUpgrade); - }); -});