diff --git a/.github/workflows/control.yml b/.github/workflows/control.yml index 636671d561..b9569540d2 100644 --- a/.github/workflows/control.yml +++ b/.github/workflows/control.yml @@ -12,6 +12,7 @@ on: jobs: control: + if: false # temporarily disable control building runs-on: snowbridge-runner env: CARGO_INCREMENTAL: 0 diff --git a/contracts/integration/ForkUpgrade202509.t.sol b/contracts/integration/ForkUpgrade202509.t.sol index 02e7c1dc68..b56431196f 100644 --- a/contracts/integration/ForkUpgrade202509.t.sol +++ b/contracts/integration/ForkUpgrade202509.t.sol @@ -1,36 +1,26 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity 0.8.34; -import {Vm} from "forge-std/Vm.sol"; import {Test} from "forge-std/Test.sol"; -import {stdJson} from "forge-std/StdJson.sol"; -import {console} from "forge-std/console.sol"; -import {UD60x18, ud60x18, unwrap} from "prb/math/src/UD60x18.sol"; - -import {IUpgradable} from "../../src/interfaces/IUpgradable.sol"; -import {IGatewayV1} from "../../src/v1/IGateway.sol"; -import {Verification} from "../../src/Verification.sol"; -import {Gateway} from "../../src/Gateway.sol"; -import {Gateway202509} from "../../src/upgrade/Gateway202509.sol"; -import {AgentExecutor} from "../../src/AgentExecutor.sol"; +import {UD60x18, unwrap} from "prb/math/src/UD60x18.sol"; +import {WETH9} from "canonical-weth/WETH9.sol"; + +import {IUpgradable} from "../src/interfaces/IUpgradable.sol"; +import {IGatewayV1} from "../src/v1/IGateway.sol"; +import {Verification} from "../src/Verification.sol"; +import {Gateway} from "../src/Gateway.sol"; +import {Gateway202509} from "../src/upgrade/Gateway202509.sol"; +import {AgentExecutor} from "../src/AgentExecutor.sol"; import { UpgradeParams, - SetOperatingModeParams, - OperatingMode, - RegisterForeignTokenParams -} from "../../src/v1/Types.sol"; -import { ChannelID, ParaID, - OperatingMode, InboundMessage, Command, - TokenInfo, MintForeignTokenParams -} from "../../src/v1/Types.sol"; -import {MultiAddress, multiAddressFromBytes32} from "../../src/v1/MultiAddress.sol"; +} from "../src/v1/Types.sol"; +import {MultiAddress, multiAddressFromBytes32} from "../src/v1/MultiAddress.sol"; import {ForkTestFixtures, SubmitMessageFixture} from "../test/utils/ForkTestFixtures.sol"; -import {WETH9} from "canonical-weth/WETH9.sol"; contract ForkUpgradeTest is Test { address private constant GATEWAY_PROXY = 0x27ca963C279c93801941e1eB8799c23f407d68e7; @@ -52,16 +42,15 @@ contract ForkUpgradeTest is Test { 0x4e241583d94b5d48a27a22064cd49b2ed6f5231d2d950e432f9b7c2e0ade52b2; address internal constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; WETH9 public weth = WETH9(payable(WETH)); + string internal constant FORK_RPC_URL = + "https://virtual.mainnet.eu.rpc.tenderly.co/61589e0a-d204-449b-b095-64366ea949cb"; event Transfer(address indexed from, address indexed to, uint256 value); function setUp() public {} function setUp23432697() public { - vm.createSelectFork( - "https://virtual.mainnet.eu.rpc.tenderly.co/dc7e68d7-5fac-4a88-a797-01ed4155f437", - 23_432_697 - ); + vm.createSelectFork(FORK_RPC_URL, 23_432_697); (UD60x18 exchangeRate, uint128 deliveryCost) = IGatewayV1(GATEWAY_PROXY).pricingParameters(); @@ -183,16 +172,14 @@ contract ForkUpgradeTest is Test { vm.expectEmit(true, false, false, false); emit IGatewayV1.OutboundMessageAccepted(paraID.into(), 1, bytes32("0x"), hex""); hoax(user, amount + fee); - IGatewayV1(address(GATEWAY_PROXY)) - .sendToken{value: amount + fee}(address(0), paraID, recipientAddress32, 1, amount); + IGatewayV1(address(GATEWAY_PROXY)).sendToken{value: amount + fee}( + address(0), paraID, recipientAddress32, 1, amount + ); assertEq(user.balance, 0); } function setUp23526799() public { - vm.createSelectFork( - "https://virtual.mainnet.eu.rpc.tenderly.co/1d4ab8c5-01fe-45a7-8583-8b4925e5a435", - 23_526_799 - ); + vm.createSelectFork(FORK_RPC_URL, 23_526_799); // Mock call to Verification.verifyCommitment to bypass BEEFY verification. // Note that after the gateway is upgraded, the gateway will be linked to a new Verification @@ -311,8 +298,9 @@ contract ForkUpgradeTest is Test { bytes32(0x65b3c8970f6316e368291bddf21059f298f18ad356faafed0ac19244f15dc67f), hex"" ); - IGatewayV1(address(GATEWAY_PROXY)) - .sendToken{value: fee}(DOT, paraID, recipientAddress32, 1, amount); + IGatewayV1(address(GATEWAY_PROXY)).sendToken{value: fee}( + DOT, paraID, recipientAddress32, 1, amount + ); } // Send WETH can work with the upgraded Gateway @@ -337,7 +325,8 @@ contract ForkUpgradeTest is Test { emit IGatewayV1.TokenSent(WETH, user, paraID, recipientAddress32, amount); vm.expectEmit(true, false, false, false); emit IGatewayV1.OutboundMessageAccepted(paraID.into(), 1, bytes32("0x"), hex""); - IGatewayV1(address(GATEWAY_PROXY)) - .sendToken{value: fee}(WETH, paraID, recipientAddress32, 1, amount); + IGatewayV1(address(GATEWAY_PROXY)).sendToken{value: fee}( + WETH, paraID, recipientAddress32, 1, amount + ); } } diff --git a/contracts/integration/ForkUpgrade202603.t.sol b/contracts/integration/ForkUpgrade202603.t.sol new file mode 100644 index 0000000000..416da6e2d2 --- /dev/null +++ b/contracts/integration/ForkUpgrade202603.t.sol @@ -0,0 +1,304 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity 0.8.34; + +import {Test} from "forge-std/Test.sol"; +import {WETH9} from "canonical-weth/WETH9.sol"; + +import {IUpgradable} from "../src/interfaces/IUpgradable.sol"; +import {IGatewayV1} from "../src/v1/IGateway.sol"; +import {IGatewayV2} from "../src/v2/IGateway.sol"; +import {Verification} from "../src/Verification.sol"; +import {Gateway} from "../src/Gateway.sol"; +import { + UpgradeParams, + ChannelID, + ParaID, + InboundMessage, + Command, + MintForeignTokenParams +} from "../src/v1/Types.sol"; +import {MultiAddress, multiAddressFromBytes32} from "../src/v1/MultiAddress.sol"; +import {Payload, Asset, makeRawXCM} from "../src/v2/Types.sol"; +import { + ForkTestFixtures, + SubmitMessageFixture, + SubmitV2MessageFixture +} from "../test/utils/ForkTestFixtures.sol"; + +contract ForkUpgrade202603Test is Test { + address private constant GATEWAY_PROXY = 0x27ca963C279c93801941e1eB8799c23f407d68e7; + address private constant BEEFY_CLIENT = 0x7cfc5C8b341991993080Af67D940B6aD19a010E1; + address private constant GATEWAY_LOGIC_202602 = 0x36e74FCAAcb07773b144Ca19Ef2e32Fc972aC50b; + + // NOTE: Can use tenderly transaction debugger to retrieve existing library address + address private constant VERIFICATION_ADDR_V1 = 0x4058bE4f048F55F1e9C88da09738070C0a7F1593; + bytes4 private constant VERIFICATION_SELECTOR_V1 = 0x2db72616; + + ChannelID internal constant GOVERNANCE_CHANNEL = + ChannelID.wrap(0x0000000000000000000000000000000000000000000000000000000000000001); + ChannelID internal constant ASSETHUB_CHANNEL = + ChannelID.wrap(0xc173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539); + bytes32 internal constant ASSETHUB_AGENT_ID = + 0x81c5ab2571199e3188135178f3c2c8e2d268be1313d029b30f534fa579b69b79; + address internal constant assetHubAgent = 0xd803472c47a87D7B63E888DE53f03B4191B846a8; + address internal constant DOT = 0x196C20DA81Fbc324EcdF55501e95Ce9f0bD84d14; + bytes32 internal constant DOT_ID = + 0x4e241583d94b5d48a27a22064cd49b2ed6f5231d2d950e432f9b7c2e0ade52b2; + address internal constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; + WETH9 public weth = WETH9(payable(WETH)); + + string internal constant FORK_RPC_URL = + "https://virtual.mainnet.eu.rpc.tenderly.co/61589e0a-d204-449b-b095-64366ea949cb"; + + event Transfer(address indexed from, address indexed to, uint256 value); + + function setUp() public {} + + function selectFork(uint256 blockNumber) public { + vm.createSelectFork(FORK_RPC_URL, blockNumber); + } + + // This function is used to upgrade the gateway to the new implementation. It can be called + // at the beginning of other tests in this contract to ensure that the gateway is upgraded + // before running the test logic. + function upgradeTo202602() public { + (uint64 inbound, uint64 outbound) = + IGatewayV1(GATEWAY_PROXY).channelNoncesOf(ASSETHUB_CHANNEL); + + uint256 balance = assetHubAgent.balance; + + // Mock call to Verification.verifyCommitment to bypass BEEFY verification. + // Note that after the gateway is upgraded, the gateway will be linked to a new Verification + // library, essentially undoing this mock. + vm.mockCall( + VERIFICATION_ADDR_V1, + abi.encodeWithSelector(VERIFICATION_SELECTOR_V1), + abi.encode(true) + ); + + // Use already deployed implementation contract + address newLogic = GATEWAY_LOGIC_202602; + + // Prepare upgrade command + UpgradeParams memory params = UpgradeParams({ + impl: newLogic, implCodeHash: newLogic.codehash, initParams: bytes("") + }); + + (bytes32[] memory proof1, Verification.Proof memory proof2) = + ForkTestFixtures.makeMockProofs(); + (uint64 nonce,) = IGatewayV1(GATEWAY_PROXY).channelNoncesOf(GOVERNANCE_CHANNEL); + + vm.expectEmit(); + emit IUpgradable.Upgraded(newLogic); + + // Issue the upgrade + IGatewayV1(GATEWAY_PROXY) + .submitV1( + InboundMessage( + GOVERNANCE_CHANNEL, + nonce + 1, + Command.Upgrade, + abi.encode(params), + 100_000, + block.basefee, + 0, + keccak256("message-id") + ), + proof1, + proof2 + ); + + // Governance channel inbound nonce should have incremented by 1 + (uint64 nonceAfter,) = IGatewayV1(GATEWAY_PROXY).channelNoncesOf(GOVERNANCE_CHANNEL); + assertEq(nonceAfter, nonce + 1); + + // Asset hub channel nonces should be unchanged + (uint64 inboundAfter, uint64 outboundAfter) = + IGatewayV1(GATEWAY_PROXY).channelNoncesOf(ASSETHUB_CHANNEL); + assertEq(inboundAfter, inbound); + assertEq(outboundAfter, outbound); + + address agent = IGatewayV1(GATEWAY_PROXY).agentOf(ASSETHUB_AGENT_ID); + assertEq(agent, assetHubAgent); + + // Asset hub agent balance should be unchanged + uint256 balanceAfter = assetHubAgent.balance; + assertEq(balanceAfter, balance); + } + + function testUpgradedGateway202602StillAcceptsV2UnlockNativeEther() public { + selectFork(24_677_447); + upgradeTo202602(); + SubmitV2MessageFixture memory fixture = ForkTestFixtures.makeSubmitV2MessageFixture( + "/test/data/mainnet-gateway-submitv2-unlock-ether.json" + ); + + // Expect the gateway to emit InboundMessageDispatched event + vm.expectEmit(true, true, true, true); + emit IGatewayV2.InboundMessageDispatched( + fixture.message.nonce, fixture.message.topic, true, fixture.rewardAddress + ); + + address relayer = makeAddr("relayer"); + vm.deal(relayer, 10 ether); + + vm.prank(relayer); + IGatewayV2(address(GATEWAY_PROXY)) + .v2_submit( + fixture.message, fixture.leafProof, fixture.headerProof, fixture.rewardAddress + ); + } + + function testUpgradedGateway202602StillAcceptsV1UnlockNativeEther() public { + selectFork(24_681_921); + upgradeTo202602(); + SubmitMessageFixture memory fixture = ForkTestFixtures.makeSubmitMessageFixture( + "/test/data/mainnet-gateway-submitv1-unlock-ether-202603.json" + ); + + // Expect the gateway to emit InboundMessageDispatched event + vm.expectEmit(true, true, true, true); + emit IGatewayV1.InboundMessageDispatched( + fixture.message.channelID, fixture.message.nonce, fixture.message.id, true + ); + + address relayer = makeAddr("relayer"); + vm.deal(relayer, 10 ether); + + vm.prank(relayer); + IGatewayV1(address(GATEWAY_PROXY)) + .submitV1(fixture.message, fixture.leafProof, fixture.headerProof); + } + + function testUpgradedGateway202602StillCanSendEtherWithV1SendToken() public { + selectFork(24_681_921); + upgradeTo202602(); + // Create a mock user + address user = makeAddr("user"); + uint128 amount = 1; + ParaID paraID = ParaID.wrap(1000); + + MultiAddress memory recipientAddress32 = multiAddressFromBytes32(keccak256("recipient")); + + uint128 fee = + uint128(IGatewayV1(address(GATEWAY_PROXY)).quoteSendTokenFee(address(0), paraID, 1)); + assertTrue(fee > 0); + // This addresses the missing AssetsStorage.Layout migration bug, which was causing the fee to be unreasonably high. + assertTrue(fee < 0.01 ether); + + uint256 balanceBefore = assetHubAgent.balance; + + vm.expectEmit(); + emit IGatewayV1.TokenSent(address(0), user, paraID, recipientAddress32, amount); + vm.expectEmit(true, false, false, false); + emit IGatewayV1.OutboundMessageAccepted(paraID.into(), 1, bytes32("0x"), hex""); + hoax(user, amount + fee); + IGatewayV1(address(GATEWAY_PROXY)).sendToken{value: amount + fee}( + address(0), paraID, recipientAddress32, 1, amount + ); + // After the sendToken call, the asset hub agent should have received the amount, and the user's balance should be 0. + uint256 balanceAfter = assetHubAgent.balance; + assertEq(balanceAfter, balanceBefore + amount); + assertEq(user.balance, 0); + } + + function testUpgradedGateway202602StillCanSendEtherWithV2SendMessage() public { + selectFork(24_681_921); + upgradeTo202602(); + // Create a mock user + address user = makeAddr("user"); + uint128 amount = uint128(0.1 ether); + ParaID paraID = ParaID.wrap(1000); + + uint128 executionFee = 0.01 ether; + uint128 relayerFee = 0.01 ether; + uint128 fee = executionFee + relayerFee; + + uint256 balanceBefore = assetHubAgent.balance; + uint64 nonceBefore = IGatewayV2(address(GATEWAY_PROXY)).v2_outboundNonce(); + + vm.expectEmit(true, false, false, false); + emit IGatewayV2.OutboundMessageAccepted( + 1, + Payload({ + origin: user, + assets: new Asset[](0), + xcm: makeRawXCM(""), + claimer: "", + value: amount, + executionFee: executionFee, + relayerFee: relayerFee + }) + ); + + hoax(user, amount + fee); + IGatewayV2(payable(address(GATEWAY_PROXY))).v2_sendMessage{value: amount + fee}( + "", new bytes[](0), "", executionFee, relayerFee + ); + + // Verify asset balances + assertEq(assetHubAgent.balance, balanceBefore + amount + fee); + assertEq(IGatewayV2(address(GATEWAY_PROXY)).v2_outboundNonce(), nonceBefore + 1); + } + + function testUpgradedGateway202602StillAcceptsV1MintDOT() public { + selectFork(24_683_314); + upgradeTo202602(); + SubmitMessageFixture memory fixture = ForkTestFixtures.makeSubmitMessageFixture( + "/test/data/mainnet-gateway-submitv1-mint-dot-202603.json" + ); + + // Expect the gateway to emit InboundMessageDispatched event + vm.expectEmit(true, true, true, true); + emit IGatewayV1.InboundMessageDispatched( + fixture.message.channelID, fixture.message.nonce, fixture.message.id, true + ); + + address relayer = makeAddr("relayer"); + vm.deal(relayer, 10 ether); + + vm.prank(relayer); + IGatewayV1(address(GATEWAY_PROXY)) + .submitV1(fixture.message, fixture.leafProof, fixture.headerProof); + } + + // Send DOT can work with the upgraded Gateway + function testUpgradedGatewayStillCanSendDOT() public { + selectFork(24_683_314); + upgradeTo202602(); + address user = 0x302F0B71B8aD3CF6dD90aDb668E49b2168d652fd; + vm.deal(user, 1 ether); + + vm.prank(address(GATEWAY_PROXY)); + uint128 amount = 100; + MintForeignTokenParams memory params = + MintForeignTokenParams({foreignTokenID: DOT_ID, recipient: user, amount: amount}); + + vm.expectEmit(true, true, false, false); + emit Transfer(address(0), user, amount); + + ParaID paraID = ParaID.wrap(1000); + Gateway(address(GATEWAY_PROXY)) + .v1_handleMintForeignToken(paraID.into(), abi.encode(params)); + + MultiAddress memory recipientAddress32 = multiAddressFromBytes32(keccak256("recipient")); + + uint128 fee = uint128(IGatewayV1(address(GATEWAY_PROXY)).quoteSendTokenFee(DOT, paraID, 1)); + assertTrue(fee > 0); + assertTrue(fee < 0.01 ether); + + vm.prank(user); + vm.expectEmit(); + emit IGatewayV1.TokenSent(DOT, user, paraID, recipientAddress32, amount); + vm.expectEmit(true, true, true, false); + emit IGatewayV1.OutboundMessageAccepted( + paraID.into(), + 11_110, + bytes32(0x688eefdb5afe6d8dfbccd6746853dd9ec90695bccaa7a37ea624f1b4d951fbdd), + hex"" + ); + IGatewayV1(address(GATEWAY_PROXY)).sendToken{value: fee}( + DOT, paraID, recipientAddress32, 1, amount + ); + } +} diff --git a/contracts/scripts/upgrade/DeployGateway.sol b/contracts/scripts/upgrade/DeployGateway.sol index 3fd9e0f120..d9150b9f62 100644 --- a/contracts/scripts/upgrade/DeployGateway.sol +++ b/contracts/scripts/upgrade/DeployGateway.sol @@ -22,8 +22,7 @@ contract DeployGateway is Script { keccak256(abi.encodePacked(vm.envString("SNOWBRIDGE_DEPLOY_STAGE"))) == keccak256(abi.encodePacked("polkadot_mainnet")) ) { - // Todo: Update Beefy client address on Polkadot mainnet with the correct one before deploying. - address beefyClient = 0x1817874feAb3ce053d0F40AbC23870DB35C2AFfc; + address beefyClient = 0x7cfc5C8b341991993080Af67D940B6aD19a010E1; gatewayLogic = new Gateway202602(address(beefyClient), address(executor)); } else if ( keccak256(abi.encodePacked(vm.envString("SNOWBRIDGE_DEPLOY_STAGE"))) diff --git a/contracts/test/data/mainnet-gateway-submitv1-mint-dot-202603.json b/contracts/test/data/mainnet-gateway-submitv1-mint-dot-202603.json new file mode 100644 index 0000000000..868a2b4c9f --- /dev/null +++ b/contracts/test/data/mainnet-gateway-submitv1-mint-dot-202603.json @@ -0,0 +1,83 @@ +{ + "tx": "0xdec110d535b748acc1842a872489ef749b842d622c54f015b92805b8b79be64c", + "input": { + "message": { + "channelID": "0xc173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539", + "nonce": 8800, + "command": 11, + "params": "0x4e241583d94b5d48a27a22064cd49b2ed6f5231d2d950e432f9b7c2e0ade52b2000000000000000000000000091229c0b1465dd8d9977f1c45d368bbc34b84050000000000000000000000000000000000000000000000000000000077359400", + "maxDispatchGas": 100000, + "maxFeePerGas": "7000000000", + "reward": "250000000000000", + "id": "0x732566be131e79207c3dbc9aaa2d78c02d4e1762791dd8d7bba6c104734450cb" + }, + "leafProof": [], + "headerProof": { + "header": { + "parentHash": "0x371f1b6a9255a41d91594b834ec919c38c3a1015f27ce1d1e4d753d095de226d", + "number": "7254205", + "stateRoot": "0x141f9bef7a2b486080074d733703797713e24f6335761fa18955494684f95138", + "extrinsicsRoot": "0x609de59edc173e4fcb9fd7b197ad45c149bae16e8a60fd3c937feba6a5ab7d43", + "digestItems": [ + { + "kind": 6, + "consensusEngineID": "0x61757261", + "data": "0xe587cf0800000000" + }, + { + "kind": 4, + "consensusEngineID": "0x52505352", + "data": "0xbbbb36ca95bbe2380d05d4019c7b8d14c37f8498449032268985083a8046e207ce174007" + }, + { + "kind": 0, + "consensusEngineID": "0x00000000", + "data": "0x0000b7529c64ba5f6059a34b7f4678ee13ab3b55466916fbad17c82ac3d902803c" + }, + { + "kind": 5, + "consensusEngineID": "0x61757261", + "data": "0x6e170fab9722501d0771aa4b3e30199a5a4d001f5ff33cdf245b049e3f8ac223701ac09b800a47b7a71e0a735e0e99bd6409b61f035773b2be78d6d75ae0ff8a" + } + ] + }, + "headProof": { + "pos": "1", + "width": "20", + "proof": [ + "0x63d8fa3c89df614d4940b81a38da83b3335785d0a11f8321c98a7cee0897616a", + "0xcc8139a0fcd00a32f2d712a9783a39dbbe6f1ae9b56816bb05f5d544e958d16d", + "0x273f53142a94901eee0adac246af28d29e969cf69ab27182ffcd0cf408aea90c", + "0x220023867ffc635208130e53601d7c52bc3388a3192990a048039ff09f17a4e5", + "0x40809a077e9c9120ec96d0b0503bd397f6a6165b607c673d845a3ea17d119e35" + ] + }, + "leafPartial": { + "version": 0, + "parentNumber": 30410229, + "parentHash": "0xf4d0f19e954b876c1eac9bc0ada4df34f3bd39203bb08adf08afcf99bd9aeb95", + "nextAuthoritySetID": 4549, + "nextAuthoritySetLen": 600, + "nextAuthoritySetRoot": "0x8d6890d7b2391407f114e030023ae4ac59867b79a8fcd82a9263ecadfee4b4c0" + }, + "leafProof": [ + "0x5819c44830f8499757c67811714fc26c95bff39b3309a1a0f6daa459dd57cacb", + "0xdbfa0bd24cc94e54693ff4f0b959363b1abdacabb088c6c8d2d7cf65d4a892b3", + "0xb3e6ccb777f4f747d02a431e4bfb447ebf3a048045a26f62fe66626446c7a0a8", + "0x48e989ded8f2644a4037a542c9feb99740203bcdc0e7ec268fe2c4ce7833530e", + "0xecce75d9568d7e76f779ed57be915da662b7d7870d2f6bcfbd634e33be4d1b76", + "0x19d9989ffa3a03fd5be26e51679c27c0550705913844a9da19d09eec2d25b610", + "0x303c45636f8a9f355193e94a26ae748f007de2b6370d375c55acf8de4d34eef8", + "0xf3147e84a698405b7b49c98f2a0ed927f48df5ea52a2bc28c6c7e62ef49029a9", + "0x8ce3521d9b020f8e74c1cdbfaf8cbedb2d72b86cacc52a54ce11848fa63ca89e", + "0x4ec7ed25260978dc3ea42c8addf76bd8a7533019aebece7027bc6bdde98621cb", + "0x3d792b7b51c18649f344cf34235e249a10ed30fd8e2b5687739e8278725ac743", + "0x75929cc6fa0d17551af25fa12f921e19c8499f269c6f6badc1789ee47ca3a18b", + "0x10f4418f4cdb65322788a70a5f76a31f5d3c1c7a84c3c425f5a739fc797eb4fc", + "0x9117d64c8b0d287eeb92c40bdaa665afee449146ada4bf325237d95c9db945f5", + "0x2258bd76e599a292375780708fc2b3ccedcf89e8ea95bb10c3ac98ccd412e2f4" + ], + "leafProofOrder": "29" + } + } +} diff --git a/contracts/test/data/mainnet-gateway-submitv1-unlock-ether-202603.json b/contracts/test/data/mainnet-gateway-submitv1-unlock-ether-202603.json new file mode 100644 index 0000000000..784f4d4241 --- /dev/null +++ b/contracts/test/data/mainnet-gateway-submitv1-unlock-ether-202603.json @@ -0,0 +1,81 @@ +{ + "tx": "0x38c57d1b35b3e204697d500e7a26b00ec52404191d70c6daa7d11ebef1ec125c", + "input": { + "message": { + "channelID": "0xc173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539", + "nonce": 8797, + "command": 9, + "params": "0x81c5ab2571199e3188135178f3c2c8e2d268be1313d029b30f534fa579b69b790000000000000000000000000000000000000000000000000000000000000000000000000000000000000000091229c0b1465dd8d9977f1c45d368bbc34b840500000000000000000000000000000000000000000000000000000002540be400", + "maxDispatchGas": 200000, + "maxFeePerGas": "7000000000", + "reward": "250000000000000", + "id": "0x80dec111ab0447b06162c6dc96c16c4afabfdc95c019926bcab44d9bc5a2b051" + }, + "leafProof": [], + "headerProof": { + "header": { + "parentHash": "0xef0d0ef141c83196c1a6badbcc08dc435d7fb66c4b8894439164d061872ff7ac", + "number": "7252876", + "stateRoot": "0x3089243f487c3c69f4c7c50e390d02a2da850f4404f83c2ea6955e946dbaeff1", + "extrinsicsRoot": "0x6775b883f5cb0d0b4a264acb3ec625357e75d21b6221c19cb6f2f2ac8850fb40", + "digestItems": [ + { + "kind": 6, + "consensusEngineID": "0x61757261", + "data": "0x8d82cf0800000000" + }, + { + "kind": 4, + "consensusEngineID": "0x52505352", + "data": "0x758f4d3a6f76674314b1a7c719ebf29d8dde9447c034970d6cb4aeaaba2c3e103eed3f07" + }, + { + "kind": 0, + "consensusEngineID": "0x00000000", + "data": "0x00cfc32445f860322addcaf3e30633fb17a7b3edf704f5ee8ddfed1f061a4c136e" + }, + { + "kind": 5, + "consensusEngineID": "0x61757261", + "data": "0x76690ced155a66830bf7ff2ce810403d002d00f2c9cda2de6861d9d2d949e24d87eeead6a04495ade5fbc387b4bfe8d3b0f665feab49f94cfdd742b69e68d480" + } + ] + }, + "headProof": { + "pos": "1", + "width": "20", + "proof": [ + "0x6cc95da9a33e30080126af9ecc9704ade0d83f71a849c6b37a90fcdd8f042144", + "0xf310427617e7939ced22219f9bf308313c446dcdd91c094129c6bf240b1ce2a3", + "0x7f7b1d7622fac4207b8f7798c56a155225a8ece4f017fb46117cc93f9c2dee74", + "0xa107dca3f82d9cae053d1fd9280e6b910856128dd421924ff3fe71e48d0ad0b7", + "0x6ea8b8ea7220db6b32a66983924fedfc504f568433ed3a339bbed12ea56d954b" + ] + }, + "leafPartial": { + "version": 0, + "parentNumber": 30407505, + "parentHash": "0x322201d29cb92525e2f82f19b2c0875840d9d4c05372b01ab01a4e4c03f937a0", + "nextAuthoritySetID": 4548, + "nextAuthoritySetLen": 600, + "nextAuthoritySetRoot": "0x8d6890d7b2391407f114e030023ae4ac59867b79a8fcd82a9263ecadfee4b4c0" + }, + "leafProof": [ + "0xcdc605e1792285844b2c009c0f463c3b141a20a0e65152663793e180e8cc008c", + "0xa1ac49221b564d900236f8ac589438339127c179a489226f16e3dfa3d8c7f99c", + "0x981726392ec4a6d2a70b73d3f2a966eb0d6f03ab3abaf949d68e721afce9e2d2", + "0x3140b64e076bb9da301e782b2134883e820d6b6906f283d3731e1872aa2035aa", + "0xd2a528c1441644727304532f4d70d0a7bb01a93e39dd8585cfafdd091b1fcd7a", + "0xc9973e88d97fc2d4e8600a66737d3e6af8e330f1049c014f5f479624bc7f7cba", + "0xdf0da6e17cbde4cabd2993a934911a21b8daade30566d52b6b695615318fd2f9", + "0x4ec7ed25260978dc3ea42c8addf76bd8a7533019aebece7027bc6bdde98621cb", + "0x3d792b7b51c18649f344cf34235e249a10ed30fd8e2b5687739e8278725ac743", + "0x75929cc6fa0d17551af25fa12f921e19c8499f269c6f6badc1789ee47ca3a18b", + "0x10f4418f4cdb65322788a70a5f76a31f5d3c1c7a84c3c425f5a739fc797eb4fc", + "0x9117d64c8b0d287eeb92c40bdaa665afee449146ada4bf325237d95c9db945f5", + "0x2258bd76e599a292375780708fc2b3ccedcf89e8ea95bb10c3ac98ccd412e2f4" + ], + "leafProofOrder": "5" + } + } +} diff --git a/contracts/test/data/mainnet-gateway-submitv2-unlock-ether.json b/contracts/test/data/mainnet-gateway-submitv2-unlock-ether.json new file mode 100644 index 0000000000..04fa51e630 --- /dev/null +++ b/contracts/test/data/mainnet-gateway-submitv2-unlock-ether.json @@ -0,0 +1,83 @@ +{ + "tx": "0xce9d80afa1fce6ec4f44e2da6d97f9ba6aa6b937fbd146738a7819b929f061ef", + "input": { + "message": { + "origin": "0xee4c83b021f4530e326818fcaacfc1a0c6ab213e740362c5f9e09c8b0b0165cc", + "nonce": 145, + "topic": "0x9aab3045fcbef90efca72962ac90c520e9d788d627a9bfb812693b46b969b15d", + "commands": [ + { + "kind": 2, + "gas": 200000, + "payload": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000091229c0b1465dd8d9977f1c45d368bbc34b8405000000000000000000000000000000000000000000000000000000e8d4a51000" + } + ] + }, + "leafProof": [], + "headerProof": { + "header": { + "parentHash": "0x49a23ab1c825e5e2057659d7e11f1ca16400d3234770ac4efb85059d082e36f9", + "number": "7248483", + "stateRoot": "0x95fd9d3a660c139729d6c7c80106631cfa910834bd189ff413acfcada0daa661", + "extrinsicsRoot": "0xc61407a1b0392fa12c08b2441a11b3e840e6fa388a5d3616d5708543e3fc28d3", + "digestItems": [ + { + "kind": 6, + "consensusEngineID": "0x61757261", + "data": "0x0971cf0800000000" + }, + { + "kind": 4, + "consensusEngineID": "0x52505352", + "data": "0x7de68b439f4576d5a642eeca173bda8886c12517128a8d119b932f99dac67b146e613f07" + }, + { + "kind": 0, + "consensusEngineID": "0x00000000", + "data": "0x01f1f4541830f031c2ac0a690b28cb61072573cbbe73ed78f71ca52a78f31f9fc1" + }, + { + "kind": 5, + "consensusEngineID": "0x61757261", + "data": "0x4a119a5d7ca7a8505a63e962598b7cca70da4ac6c06e37e06346c574b739a74cb7fedf43ae14c9c6b5e32fb5c93a8e36eed026b11fa8ec479d7a1d740d40b189" + } + ] + }, + "headProof": { + "pos": "1", + "width": "20", + "proof": [ + "0x384fe0e347d1f4c7225d3345ebb2acb56fff1008e5a1c064b0698994c40c71a7", + "0x3770102016b56eecb2cc3a0ab7720be3d5cb8c7deb3e730683d7a3789da34863", + "0x1fd681ba3cbdda218866e50718e43359d225849cdcf220e38fa78a1b0913700d", + "0x608a2817ef9694e798a49dbb5bfdb213c5fd7e3f6d810ee8cdd3e04de522d64e", + "0xb6a5272244c519ee532b0f66dad20ff7ee55e55810620f31741fb4fd774896ec" + ] + }, + "leafPartial": { + "version": 0, + "parentNumber": 30398557, + "parentHash": "0x3aff2cbbd26320efa62e78c51b305c1ddfe004f03b12d3f3c3c42ddb99ccf165", + "nextAuthoritySetID": 4544, + "nextAuthoritySetLen": 600, + "nextAuthoritySetRoot": "0x06cc29698a6a1ee691fdebf8ca0fc8976c2c1c5e7bb509878401f44c79b2a7a9" + }, + "leafProof": [ + "0x6ce8d2d8f6a45312b77bdd865e157d486155d39485bdf44c52c158929cbded99", + "0x5280687540b94e410e0157028543f1f106e0c100c49720173c42db92bcd13e1e", + "0x22bf2a9b534b8c5b136bab1c1d0245d717fafe604cddf0d0fb8b81a478387f75", + "0xcb224d14ed0a9d202a08e962de2055a34827e8f3899f7204527646dd11483d75", + "0x4bece458b56801861a78f034df7a71569a438a50eb7d55448b420c8946483bac", + "0xa2c21a5ecf21cc44511dcaa7fdf326884abc777aff5f05f8873356d3dd4ddf99", + "0x752766cd3983261e8adc0ab6b23b16673f390ecbae23e080e27b8578641fc692", + "0x3d792b7b51c18649f344cf34235e249a10ed30fd8e2b5687739e8278725ac743", + "0x75929cc6fa0d17551af25fa12f921e19c8499f269c6f6badc1789ee47ca3a18b", + "0x10f4418f4cdb65322788a70a5f76a31f5d3c1c7a84c3c425f5a739fc797eb4fc", + "0x9117d64c8b0d287eeb92c40bdaa665afee449146ada4bf325237d95c9db945f5", + "0x2258bd76e599a292375780708fc2b3ccedcf89e8ea95bb10c3ac98ccd412e2f4" + ], + "leafProofOrder": "13" + }, + "rewardAddress": "0x2a975dad1c0fb19221a9288a0ae4b63ed29f3c625a73578117dde65482b8fc23" + } +} diff --git a/contracts/test/utils/ForkTestFixtures.sol b/contracts/test/utils/ForkTestFixtures.sol index a837a26b34..69239b52f3 100644 --- a/contracts/test/utils/ForkTestFixtures.sol +++ b/contracts/test/utils/ForkTestFixtures.sol @@ -5,11 +5,9 @@ import {Vm} from "forge-std/Vm.sol"; import {stdJson} from "forge-std/StdJson.sol"; import {Verification} from "../../src/Verification.sol"; -import { - ChannelID, - InboundMessage, - Command -} from "../../src/v1/Types.sol"; +import {ChannelID, InboundMessage, Command} from "../../src/v1/Types.sol"; + +import {InboundMessage as InboundMessageV2, Command as CommandV2} from "../../src/v2/Types.sol"; struct SubmitMessageFixture { InboundMessage message; @@ -17,17 +15,20 @@ struct SubmitMessageFixture { Verification.Proof headerProof; } +struct SubmitV2MessageFixture { + InboundMessageV2 message; + bytes32[] leafProof; + Verification.Proof headerProof; + bytes32 rewardAddress; +} + library ForkTestFixtures { using stdJson for string; Vm public constant vm = Vm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); // Make mock proofs for the upgrade message - function makeMockProofs() - internal - pure - returns (bytes32[] memory, Verification.Proof memory) - { + function makeMockProofs() internal pure returns (bytes32[] memory, Verification.Proof memory) { bytes32[] memory proof1 = new bytes32[](1); proof1[0] = bytes32(0x2f9ee6cfdf244060dc28aa46347c5219e303fc95062dd672b4e406ca5c29764b); @@ -111,9 +112,76 @@ library ForkTestFixtures { }); SubmitMessageFixture memory fixture = SubmitMessageFixture({ + message: message, leafProof: leafProof, headerProof: headerProof + }); + + return fixture; + } + + // Create a fixture from real-world mainnet transactions + function makeSubmitV2MessageFixture(string memory fixturePath) + internal + view + returns (SubmitV2MessageFixture memory) + { + // Read the test data + string memory data = vm.readFile(string.concat(vm.projectRoot(), fixturePath)); + + // Parse message data + CommandV2[] memory commands = new CommandV2[](1); + commands[0] = CommandV2({ + kind: uint8(data.readUint(".input.message.commands[0].kind")), + gas: uint64(data.readUint(".input.message.commands[0].gas")), + payload: data.readBytes(".input.message.commands[0].payload") + }); + + InboundMessageV2 memory message = InboundMessageV2({ + origin: data.readBytes32(".input.message.origin"), + nonce: uint64(data.readUint(".input.message.nonce")), + topic: data.readBytes32(".input.message.topic"), + commands: commands + }); + + // Parse proof data + bytes32[] memory leafProof = new bytes32[](0); // The test data has empty leaf proof + + // Parse header proof + Verification.ParachainHeader memory header = parseParachainHeader(data); + + Verification.HeadProof memory headProof = Verification.HeadProof({ + pos: uint256(data.readUint(".input.headerProof.headProof.pos")), + width: uint256(data.readUint(".input.headerProof.headProof.width")), + proof: data.readBytes32Array(".input.headerProof.headProof.proof") + }); + + Verification.MMRLeafPartial memory leafPartial = Verification.MMRLeafPartial({ + version: uint8(data.readUint(".input.headerProof.leafPartial.version")), + parentNumber: uint32(data.readUint(".input.headerProof.leafPartial.parentNumber")), + parentHash: data.readBytes32(".input.headerProof.leafPartial.parentHash"), + nextAuthoritySetID: uint64( + data.readUint(".input.headerProof.leafPartial.nextAuthoritySetID") + ), + nextAuthoritySetLen: uint32( + data.readUint(".input.headerProof.leafPartial.nextAuthoritySetLen") + ), + nextAuthoritySetRoot: data.readBytes32( + ".input.headerProof.leafPartial.nextAuthoritySetRoot" + ) + }); + + Verification.Proof memory headerProof = Verification.Proof({ + header: header, + headProof: headProof, + leafPartial: leafPartial, + leafProof: data.readBytes32Array(".input.headerProof.leafProof"), + leafProofOrder: uint256(data.readUint(".input.headerProof.leafProofOrder")) + }); + + SubmitV2MessageFixture memory fixture = SubmitV2MessageFixture({ message: message, leafProof: leafProof, - headerProof: headerProof + headerProof: headerProof, + rewardAddress: data.readBytes32(".input.rewardAddress") }); return fixture; diff --git a/control/.gitignore b/control/.gitignore index fa868a60af..596a3879da 100644 --- a/control/.gitignore +++ b/control/.gitignore @@ -13,3 +13,4 @@ /scratch chopsticks-execute-upgrade.js +runtimes/**/*metadata.bin diff --git a/control/preimage/src/main.rs b/control/preimage/src/main.rs index e0203e216d..a1c0e7bcee 100644 --- a/control/preimage/src/main.rs +++ b/control/preimage/src/main.rs @@ -73,6 +73,9 @@ pub enum Command { MintFeb2026, /// Set BridgeHubEthereumBaseFeeV2 on Paseo SetPaseoFeeV2, + /// Upgrade to FiatShamir on Polkadot + #[command(alias = "upgrade-202603")] + Upgrade202603, } #[derive(Debug, Args)] @@ -552,6 +555,24 @@ async fn run() -> Result<(), Box> { send_xcm_asset_hub(&context, vec![outbound_fee_call]).await? } } + Command::Upgrade202603 => { + #[cfg(not(feature = "polkadot"))] + panic!("Upgrade202603 only for polkadot runtime."); + + #[cfg(feature = "polkadot")] + { + // Upgrade logic gateway + let upgrade_call = commands::upgrade(&UpgradeArgs { + logic_address: address!("36e74FCAAcb07773b144Ca19Ef2e32Fc972aC50b"), + logic_code_hash: FixedBytes::from_slice(&hex!( + "e3cfcc0042ad4c819c627fb2a84ba0822d67747a8618a4e1c4eb0c5112b17903" + )), + initializer_params: Default::default(), + initializer_gas: 100000, + }); + send_xcm_bridge_hub(&context, vec![upgrade_call]).await? + } + } }; #[cfg(any(feature = "westend", feature = "paseo"))] diff --git a/control/runtimes/asset-hub-kusama/asset-hub-metadata.bin b/control/runtimes/asset-hub-kusama/asset-hub-metadata.bin deleted file mode 100644 index 92c0b929f1..0000000000 Binary files a/control/runtimes/asset-hub-kusama/asset-hub-metadata.bin and /dev/null differ diff --git a/control/runtimes/asset-hub-paseo/asset-hub-metadata.bin b/control/runtimes/asset-hub-paseo/asset-hub-metadata.bin deleted file mode 100644 index 86306431a2..0000000000 Binary files a/control/runtimes/asset-hub-paseo/asset-hub-metadata.bin and /dev/null differ diff --git a/control/runtimes/asset-hub-polkadot/asset-hub-metadata.bin b/control/runtimes/asset-hub-polkadot/asset-hub-metadata.bin deleted file mode 100644 index 7debbba656..0000000000 Binary files a/control/runtimes/asset-hub-polkadot/asset-hub-metadata.bin and /dev/null differ diff --git a/control/runtimes/asset-hub-westend/asset-hub-metadata.bin b/control/runtimes/asset-hub-westend/asset-hub-metadata.bin deleted file mode 100644 index 3e814618e8..0000000000 Binary files a/control/runtimes/asset-hub-westend/asset-hub-metadata.bin and /dev/null differ diff --git a/control/runtimes/bridge-hub-kusama/bridge-hub-metadata.bin b/control/runtimes/bridge-hub-kusama/bridge-hub-metadata.bin deleted file mode 100644 index 89cde4633c..0000000000 Binary files a/control/runtimes/bridge-hub-kusama/bridge-hub-metadata.bin and /dev/null differ diff --git a/control/runtimes/bridge-hub-paseo/bridge-hub-metadata.bin b/control/runtimes/bridge-hub-paseo/bridge-hub-metadata.bin deleted file mode 100644 index 6a79097507..0000000000 Binary files a/control/runtimes/bridge-hub-paseo/bridge-hub-metadata.bin and /dev/null differ diff --git a/control/runtimes/bridge-hub-polkadot/bridge-hub-metadata.bin b/control/runtimes/bridge-hub-polkadot/bridge-hub-metadata.bin deleted file mode 100644 index 5b3b6a1c63..0000000000 Binary files a/control/runtimes/bridge-hub-polkadot/bridge-hub-metadata.bin and /dev/null differ diff --git a/control/runtimes/bridge-hub-westend/bridge-hub-metadata.bin b/control/runtimes/bridge-hub-westend/bridge-hub-metadata.bin deleted file mode 100644 index c994f0cf82..0000000000 Binary files a/control/runtimes/bridge-hub-westend/bridge-hub-metadata.bin and /dev/null differ diff --git a/control/runtimes/kusama/polkadot-metadata.bin b/control/runtimes/kusama/polkadot-metadata.bin deleted file mode 100644 index 74bc9e55f5..0000000000 Binary files a/control/runtimes/kusama/polkadot-metadata.bin and /dev/null differ diff --git a/control/runtimes/paseo/polkadot-metadata.bin b/control/runtimes/paseo/polkadot-metadata.bin deleted file mode 100644 index 01dda0f2b2..0000000000 Binary files a/control/runtimes/paseo/polkadot-metadata.bin and /dev/null differ diff --git a/control/runtimes/polkadot/polkadot-metadata.bin b/control/runtimes/polkadot/polkadot-metadata.bin deleted file mode 100644 index c1e193743c..0000000000 Binary files a/control/runtimes/polkadot/polkadot-metadata.bin and /dev/null differ diff --git a/control/runtimes/westend/polkadot-metadata.bin b/control/runtimes/westend/polkadot-metadata.bin deleted file mode 100644 index ffc424d542..0000000000 Binary files a/control/runtimes/westend/polkadot-metadata.bin and /dev/null differ diff --git a/control/update-runtimes.sh b/control/update-runtimes.sh index 00d52961f5..c5d52be2a9 100755 --- a/control/update-runtimes.sh +++ b/control/update-runtimes.sh @@ -1,3 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail networks=( polkadot @@ -6,17 +8,17 @@ networks=( paseo ) -for network in ${networks[@]}; do +for network in "${networks[@]}"; do echo "Updating network $network" - subxt metadata --url wss://$network-rpc.n.dwellir.com -f bytes -o runtimes/$network/polkadot-metadata.bin - subxt metadata --url wss://asset-hub-$network-rpc.n.dwellir.com -f bytes -o runtimes/asset-hub-$network/asset-hub-metadata.bin + subxt metadata --url "wss://$network-rpc.n.dwellir.com" -f bytes -o "runtimes/$network/polkadot-metadata.bin" + subxt metadata --url "wss://asset-hub-$network-rpc.n.dwellir.com" -f bytes -o "runtimes/asset-hub-$network/asset-hub-metadata.bin" - bh_metadata=runtimes/bridge-hub-$network/bridge-hub-metadata.bin - bh_url=wss://bridge-hub-$network-rpc.n.dwellir.com + bh_metadata="runtimes/bridge-hub-$network/bridge-hub-metadata.bin" + bh_url="wss://bridge-hub-$network-rpc.n.dwellir.com" if [ "$network" = "paseo" ]; then - bh_url=wss://bridge-hub-paseo.dotters.network + bh_url="wss://bridge-hub-paseo.dotters.network" fi - subxt metadata --url $bh_url -f bytes -o $bh_metadata + subxt metadata --url "$bh_url" -f bytes -o "$bh_metadata" done diff --git a/web/packages/registry/scripts/buildRegistry.ts b/web/packages/registry/scripts/buildRegistry.ts index dd4724f8e8..5ca96ceedc 100644 --- a/web/packages/registry/scripts/buildRegistry.ts +++ b/web/packages/registry/scripts/buildRegistry.ts @@ -98,8 +98,8 @@ const SNOWBRIDGE_ENV: { [env: string]: Environment } = { }, relaychainUrl: "https://polkadot-rpc.n.dwellir.com", parachains: { - "1000": "wss://asset-hub-polkadot-rpc.n.dwellir.com", - "1002": "https://bridge-hub-polkadot-rpc.n.dwellir.com", + "1000": "wss://polkadot-asset-hub-rpc.polkadot.io", + "1002": "wss://polkadot-bridge-hub-rpc.polkadot.io", "3369": "wss://polkadot-mythos-rpc.polkadot.io", "2034": "wss://hydration-rpc.n.dwellir.com", "2030": "wss://bifrost-polkadot.ibp.network",