From 55cc688f94f6e05384365d08f234c6b1766589fa Mon Sep 17 00:00:00 2001 From: ron Date: Thu, 8 Feb 2024 00:48:59 +0800 Subject: [PATCH 01/37] Change for contracts --- contracts/src/Gateway.sol | 33 +++++++++++++- contracts/src/SubstrateTypes.sol | 22 ++++++++- contracts/src/Types.sol | 17 +++++++ contracts/src/interfaces/IGateway.sol | 5 ++- contracts/test/Gateway.t.sol | 49 ++++++++++++++++++--- contracts/test/mocks/GatewayUpgradeMock.sol | 13 +++++- 6 files changed, 130 insertions(+), 9 deletions(-) diff --git a/contracts/src/Gateway.sol b/contracts/src/Gateway.sol index 55b19564d2..08084483bc 100644 --- a/contracts/src/Gateway.sol +++ b/contracts/src/Gateway.sol @@ -17,7 +17,9 @@ import { Command, MultiAddress, Ticket, - Costs + Costs, + TransactMessage, + OriginKind } from "./Types.sol"; import {IGateway} from "./interfaces/IGateway.sol"; import {IInitializable} from "./interfaces/IInitializable.sol"; @@ -27,6 +29,7 @@ import {SafeNativeTransfer} from "./utils/SafeTransfer.sol"; import {Call} from "./utils/Call.sol"; import {Math} from "./utils/Math.sol"; import {ScaleCodec} from "./utils/ScaleCodec.sol"; +import {SubstrateTypes} from "./SubstrateTypes.sol"; import { UpgradeParams, @@ -86,6 +89,7 @@ contract Gateway is IGateway, IInitializable { error InvalidAgentExecutionPayload(); error InvalidCodeHash(); error InvalidConstructorParams(); + error InvalidTransact(); // handler functions are privileged modifier onlySelf() { @@ -617,4 +621,31 @@ contract Gateway is IGateway, IInitializable { assets.assetHubCreateAssetFee = config.assetHubCreateAssetFee; assets.assetHubReserveTransferFee = config.assetHubReserveTransferFee; } + + /// @inheritdoc IGateway + function transact(ParaID destinationChain, TransactMessage calldata message) external payable { + Ticket memory ticket; + Costs memory costs; + address sender; + bytes1 originKind; + // Mapping originKind to https://github.com/Snowfork/polkadot-sdk/blob/348a1a010481002e41594ed75e5d78b7c2dbed92/polkadot/xcm/src/v2/mod.rs#L86 + // only support originKind as SovereignAccount or Xcm for now + // for Xcm the sender will be the agent of the channel which to construct `DescendOrigin` on BH + if (message.originKind == OriginKind.SovereignAccount) { + sender = msg.sender; + originKind = 0x01; + } else if (message.originKind == OriginKind.Xcm) { + Channel storage channel = _ensureChannel(destinationChain.into()); + sender = channel.agent; + originKind = 0x03; + costs.foreign = message.fee; + } else { + revert InvalidTransact(); + } + bytes memory payload = SubstrateTypes.Transact(sender, originKind, message); + ticket.dest = destinationChain; + ticket.costs = costs; + ticket.payload = payload; + _submitOutbound(ticket); + } } diff --git a/contracts/src/SubstrateTypes.sol b/contracts/src/SubstrateTypes.sol index af817ac1a1..615f692103 100644 --- a/contracts/src/SubstrateTypes.sol +++ b/contracts/src/SubstrateTypes.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.23; import {ScaleCodec} from "./utils/ScaleCodec.sol"; -import {ParaID} from "./Types.sol"; +import {ParaID, TransactMessage, OriginKind} from "./Types.sol"; /** * @title SCALE encoders for common Substrate types @@ -133,4 +133,24 @@ library SubstrateTypes { ScaleCodec.encodeU128(xcmFee) ); } + + // Arbitrary transact + function Transact(address sender, bytes1 originKind, TransactMessage memory message) + internal + view + returns (bytes memory) + { + return bytes.concat( + bytes1(0x00), + ScaleCodec.encodeU64(uint64(block.chainid)), + bytes1(0x02), + SubstrateTypes.H160(sender), + originKind, + ScaleCodec.encodeU128(message.fee), + ScaleCodec.encodeU64(message.weightAtMost.refTime), + ScaleCodec.encodeU64(message.weightAtMost.proofSize), + ScaleCodec.checkedEncodeCompactU32(message.call.length), + message.call + ); + } } diff --git a/contracts/src/Types.sol b/contracts/src/Types.sol index 93d41bc0f5..177f53bc90 100644 --- a/contracts/src/Types.sol +++ b/contracts/src/Types.sol @@ -109,3 +109,20 @@ struct TokenInfo { bool isRegistered; bytes31 __padding; } + +struct Weight { + uint64 refTime; + uint64 proofSize; +} + +enum OriginKind { + SovereignAccount, + Xcm +} + +struct TransactMessage { + OriginKind originKind; + uint128 fee; + Weight weightAtMost; + bytes call; +} diff --git a/contracts/src/interfaces/IGateway.sol b/contracts/src/interfaces/IGateway.sol index e0d4d81da2..51e9eece35 100644 --- a/contracts/src/interfaces/IGateway.sol +++ b/contracts/src/interfaces/IGateway.sol @@ -2,7 +2,7 @@ // SPDX-FileCopyrightText: 2023 Snowfork pragma solidity 0.8.23; -import {OperatingMode, InboundMessage, ParaID, ChannelID, MultiAddress} from "../Types.sol"; +import {OperatingMode, InboundMessage, ParaID, ChannelID, MultiAddress, TransactMessage} from "../Types.sol"; import {Verification} from "../Verification.sol"; import {UD60x18} from "prb/math/src/UD60x18.sol"; @@ -105,4 +105,7 @@ interface IGateway { uint128 destinationFee, uint128 amount ) external payable; + + /// @dev Call transact in destinationChain + function transact(ParaID destinationChain, TransactMessage calldata message) external payable; } diff --git a/contracts/test/Gateway.t.sol b/contracts/test/Gateway.t.sol index 00adbfd986..6cf6b3964f 100644 --- a/contracts/test/Gateway.t.sol +++ b/contracts/test/Gateway.t.sol @@ -42,7 +42,10 @@ import { ParaID, Command, multiAddressFromBytes32, - multiAddressFromBytes20 + multiAddressFromBytes20, + TransactMessage, + Weight, + OriginKind } from "../src/Types.sol"; import {WETH9} from "canonical-weth/WETH9.sol"; @@ -50,14 +53,17 @@ import "./mocks/GatewayUpgradeMock.sol"; import {UD60x18, ud60x18, convert} from "prb/math/src/UD60x18.sol"; contract GatewayTest is Test { - ParaID public bridgeHubParaID = ParaID.wrap(1001); - bytes32 public bridgeHubAgentID = keccak256("1001"); + ParaID public bridgeHubParaID = ParaID.wrap(1013); + bytes32 public bridgeHubAgentID = keccak256("1013"); address public bridgeHubAgent; - ParaID public assetHubParaID = ParaID.wrap(1002); - bytes32 public assetHubAgentID = keccak256("1002"); + ParaID public assetHubParaID = ParaID.wrap(1000); + bytes32 public assetHubAgentID = keccak256("1000"); address public assetHubAgent; + ParaID public penpalParaID = ParaID.wrap(2000); + bytes32 public penpalAgentID = keccak256("2000"); + address public relayer; bytes32[] public proof = [bytes32(0x2f9ee6cfdf244060dc28aa46347c5219e303fc95062dd672b4e406ca5c29764b)]; @@ -114,6 +120,14 @@ contract GatewayTest is Test { bridgeHubAgent = IGateway(address(gateway)).agentOf(bridgeHubAgentID); assetHubAgent = IGateway(address(gateway)).agentOf(assetHubAgentID); + // Initialize agent/channel for Penpal + GatewayMock(address(gateway)).createAgentPublic(abi.encode(CreateAgentParams({agentID: penpalAgentID}))); + GatewayMock(address(gateway)).createChannelPublic( + abi.encode( + CreateChannelParams({channelID: penpalParaID.into(), agentID: penpalAgentID, mode: OperatingMode.Normal}) + ) + ); + // fund the message relayer account relayer = makeAddr("relayer"); @@ -825,4 +839,29 @@ contract GatewayTest is Test { fee = IGateway(address(gateway)).quoteRegisterTokenFee(); assertEq(fee, 10000000000000000); } + + /** + * Transact + */ + function testTransactFromSovereignOrigin() public { + TransactMessage memory message = TransactMessage(OriginKind.Xcm, 1, Weight(1, 1), bytes("0x1")); + address agentAddress = IGateway(address(gateway)).agentOf(penpalAgentID); + bytes memory payload = SubstrateTypes.Transact(agentAddress, 0x03, message); + console.log(agentAddress); + console.logBytes(payload); + vm.expectEmit(true, false, false, true); + emit IGateway.OutboundMessageAccepted(penpalParaID.into(), 1, messageID, payload); + IGateway(address(gateway)).transact{value: 1 ether}(penpalParaID, message); + } + + function testTransactFromSignedOrigin() public { + TransactMessage memory message = TransactMessage(OriginKind.SovereignAccount, 1, Weight(1, 1), bytes("0x1")); + bytes memory payload = SubstrateTypes.Transact(account1, 0x01, message); + console.log(account1); + console.logBytes(payload); + vm.expectEmit(true, false, false, true); + emit IGateway.OutboundMessageAccepted(penpalParaID.into(), 1, messageID, payload); + hoax(address(account1)); + IGateway(address(gateway)).transact{value: 1 ether}(penpalParaID, message); + } } diff --git a/contracts/test/mocks/GatewayUpgradeMock.sol b/contracts/test/mocks/GatewayUpgradeMock.sol index 130ba07841..800fa85fca 100644 --- a/contracts/test/mocks/GatewayUpgradeMock.sol +++ b/contracts/test/mocks/GatewayUpgradeMock.sol @@ -2,7 +2,16 @@ // SPDX-FileCopyrightText: 2023 Snowfork pragma solidity 0.8.23; -import {Channel, InboundMessage, OperatingMode, ParaID, Command, ChannelID, MultiAddress} from "../../src/Types.sol"; +import { + Channel, + InboundMessage, + OperatingMode, + ParaID, + Command, + ChannelID, + MultiAddress, + TransactMessage +} from "../../src/Types.sol"; import {IGateway} from "../../src/interfaces/IGateway.sol"; import {IInitializable} from "../../src/interfaces/IInitializable.sol"; import {Verification} from "../../src/Verification.sol"; @@ -61,4 +70,6 @@ contract GatewayUpgradeMock is IGateway, IInitializable { function pricingParameters() external pure returns (UD60x18, uint128) { return (convert(0), uint128(0)); } + + function transact(ParaID destinationChain, TransactMessage calldata message) external payable {} } From 07395ce937185ea60c464e3788625786a7437713 Mon Sep 17 00:00:00 2001 From: ron Date: Thu, 8 Feb 2024 16:08:13 +0800 Subject: [PATCH 02/37] Convert logic for transact command --- .../primitives/router/src/inbound/mod.rs | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/parachain/primitives/router/src/inbound/mod.rs b/parachain/primitives/router/src/inbound/mod.rs index c20554c6d1..e8c0b8f0ef 100644 --- a/parachain/primitives/router/src/inbound/mod.rs +++ b/parachain/primitives/router/src/inbound/mod.rs @@ -56,6 +56,21 @@ pub enum Command { /// XCM execution fee on AssetHub fee: u128, }, + /// call arbitrary transact on dest chain + Transact { + /// The address of the sender + sender: H160, + /// OriginKind + origin_kind: OriginKind, + /// XCM execution fee on dest chain + fee: u128, + /// The ref_time part of weight_at_most + weight_ref_time: u64, + /// The proof_size part of weight_at_most + weight_proof_size: u64, + /// The payload of the transact + payload: Vec, + }, } /// Destination for bridged tokens @@ -146,6 +161,19 @@ impl Ok(Self::convert_send_token(chain_id, token, destination, amount, fee)), + V1(MessageV1 { + chain_id, + command: + Transact { sender, origin_kind, fee, weight_ref_time, weight_proof_size, payload }, + }) => Ok(Self::convert_transact( + chain_id, + sender, + origin_kind, + fee, + weight_ref_time, + weight_proof_size, + payload, + )), } } } @@ -289,6 +317,36 @@ where [GlobalConsensus(network), AccountKey20 { network: None, key: token.into() }], ) } + + fn convert_transact( + chain_id: u64, + sender: H160, + origin_kind: OriginKind, + fee: u128, + weight_ref_time: u64, + weight_proof_size: u64, + payload: Vec, + ) -> (Xcm<()>, Balance) { + let xcm_fee: Asset = (Location::parent(), fee).into(); + + let xcm: Xcm<()> = vec![ + // Change origin to the bridge. + UniversalOrigin(GlobalConsensus(Ethereum { chain_id })), + // DescendOrigin to the sender. + DescendOrigin(AccountKey20 { network: None, key: sender.into() }.into()), + // Pay for execution. + BuyExecution { fees: xcm_fee, weight_limit: Unlimited }, + // Transact on dest chain. + Transact { + origin_kind, + require_weight_at_most: Weight::from_parts(weight_ref_time, weight_proof_size), + call: payload.into(), + }, + ] + .into(); + + (xcm, fee.into()) + } } pub struct GlobalConsensusEthereumConvertsFor(PhantomData); From d41bd086724777ad4c6c3ed3d955d7985b54691c Mon Sep 17 00:00:00 2001 From: ron Date: Tue, 13 Feb 2024 21:36:33 +0800 Subject: [PATCH 03/37] Reuse msg.sender for both originKinds --- contracts/src/Gateway.sol | 21 ++++----------------- contracts/src/SubstrateTypes.sol | 14 +++++++------- contracts/src/Types.sol | 12 ++++++++++++ contracts/test/Gateway.t.sol | 10 ++++------ 4 files changed, 27 insertions(+), 30 deletions(-) diff --git a/contracts/src/Gateway.sol b/contracts/src/Gateway.sol index 08084483bc..d9fc6bcd27 100644 --- a/contracts/src/Gateway.sol +++ b/contracts/src/Gateway.sol @@ -626,23 +626,10 @@ contract Gateway is IGateway, IInitializable { function transact(ParaID destinationChain, TransactMessage calldata message) external payable { Ticket memory ticket; Costs memory costs; - address sender; - bytes1 originKind; - // Mapping originKind to https://github.com/Snowfork/polkadot-sdk/blob/348a1a010481002e41594ed75e5d78b7c2dbed92/polkadot/xcm/src/v2/mod.rs#L86 - // only support originKind as SovereignAccount or Xcm for now - // for Xcm the sender will be the agent of the channel which to construct `DescendOrigin` on BH - if (message.originKind == OriginKind.SovereignAccount) { - sender = msg.sender; - originKind = 0x01; - } else if (message.originKind == OriginKind.Xcm) { - Channel storage channel = _ensureChannel(destinationChain.into()); - sender = channel.agent; - originKind = 0x03; - costs.foreign = message.fee; - } else { - revert InvalidTransact(); - } - bytes memory payload = SubstrateTypes.Transact(sender, originKind, message); + costs.foreign = message.fee; + bytes memory payload = SubstrateTypes.Transact( + msg.sender, message.originKind.encode(), message.fee, message.weightAtMost, message.call + ); ticket.dest = destinationChain; ticket.costs = costs; ticket.payload = payload; diff --git a/contracts/src/SubstrateTypes.sol b/contracts/src/SubstrateTypes.sol index 615f692103..982f1ffab0 100644 --- a/contracts/src/SubstrateTypes.sol +++ b/contracts/src/SubstrateTypes.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.23; import {ScaleCodec} from "./utils/ScaleCodec.sol"; -import {ParaID, TransactMessage, OriginKind} from "./Types.sol"; +import {ParaID, TransactMessage, Weight, OriginKind} from "./Types.sol"; /** * @title SCALE encoders for common Substrate types @@ -135,7 +135,7 @@ library SubstrateTypes { } // Arbitrary transact - function Transact(address sender, bytes1 originKind, TransactMessage memory message) + function Transact(address sender, bytes1 originKind, uint128 fee, Weight memory weight, bytes memory call) internal view returns (bytes memory) @@ -146,11 +146,11 @@ library SubstrateTypes { bytes1(0x02), SubstrateTypes.H160(sender), originKind, - ScaleCodec.encodeU128(message.fee), - ScaleCodec.encodeU64(message.weightAtMost.refTime), - ScaleCodec.encodeU64(message.weightAtMost.proofSize), - ScaleCodec.checkedEncodeCompactU32(message.call.length), - message.call + ScaleCodec.encodeU128(fee), + ScaleCodec.encodeU64(weight.refTime), + ScaleCodec.encodeU64(weight.proofSize), + ScaleCodec.checkedEncodeCompactU32(call.length), + call ); } } diff --git a/contracts/src/Types.sol b/contracts/src/Types.sol index 177f53bc90..8f6ab119d1 100644 --- a/contracts/src/Types.sol +++ b/contracts/src/Types.sol @@ -115,11 +115,23 @@ struct Weight { uint64 proofSize; } +/// @dev OriginKind from https://github.com/Snowfork/polkadot-sdk/blob/348a1a010481002e41594ed75e5d78b7c2dbed92/polkadot/xcm/src/v2/mod.rs#L86 enum OriginKind { SovereignAccount, Xcm } +using {encode} for OriginKind global; + +function encode(OriginKind kind) pure returns (bytes1 result) { + if (kind == OriginKind.SovereignAccount) { + result = 0x01; + } else if (kind == OriginKind.Xcm) { + result = 0x03; + } + return result; +} + struct TransactMessage { OriginKind originKind; uint128 fee; diff --git a/contracts/test/Gateway.t.sol b/contracts/test/Gateway.t.sol index 6cf6b3964f..7d6dcafd63 100644 --- a/contracts/test/Gateway.t.sol +++ b/contracts/test/Gateway.t.sol @@ -843,21 +843,19 @@ contract GatewayTest is Test { /** * Transact */ - function testTransactFromSovereignOrigin() public { + function testTransactFromXcmOrigin() public { TransactMessage memory message = TransactMessage(OriginKind.Xcm, 1, Weight(1, 1), bytes("0x1")); - address agentAddress = IGateway(address(gateway)).agentOf(penpalAgentID); - bytes memory payload = SubstrateTypes.Transact(agentAddress, 0x03, message); - console.log(agentAddress); + bytes memory payload = SubstrateTypes.Transact(account1, 0x03, message.fee, message.weightAtMost, message.call); console.logBytes(payload); vm.expectEmit(true, false, false, true); emit IGateway.OutboundMessageAccepted(penpalParaID.into(), 1, messageID, payload); + hoax(address(account1)); IGateway(address(gateway)).transact{value: 1 ether}(penpalParaID, message); } function testTransactFromSignedOrigin() public { TransactMessage memory message = TransactMessage(OriginKind.SovereignAccount, 1, Weight(1, 1), bytes("0x1")); - bytes memory payload = SubstrateTypes.Transact(account1, 0x01, message); - console.log(account1); + bytes memory payload = SubstrateTypes.Transact(account1, 0x01, message.fee, message.weightAtMost, message.call); console.logBytes(payload); vm.expectEmit(true, false, false, true); emit IGateway.OutboundMessageAccepted(penpalParaID.into(), 1, messageID, payload); From 16e7cbe05c5b44ba7a69b5f9d127242e2113c359 Mon Sep 17 00:00:00 2001 From: ron Date: Tue, 13 Feb 2024 21:37:29 +0800 Subject: [PATCH 04/37] Revert to burn&teleport --- parachain/primitives/router/src/inbound/mod.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/parachain/primitives/router/src/inbound/mod.rs b/parachain/primitives/router/src/inbound/mod.rs index e8c0b8f0ef..369924881e 100644 --- a/parachain/primitives/router/src/inbound/mod.rs +++ b/parachain/primitives/router/src/inbound/mod.rs @@ -330,18 +330,21 @@ where let xcm_fee: Asset = (Location::parent(), fee).into(); let xcm: Xcm<()> = vec![ + // Teleport required fees. + ReceiveTeleportedAsset(xcm_fee.clone().into()), + // Pay for execution. + BuyExecution { fees: xcm_fee.clone(), weight_limit: Unlimited }, // Change origin to the bridge. UniversalOrigin(GlobalConsensus(Ethereum { chain_id })), // DescendOrigin to the sender. DescendOrigin(AccountKey20 { network: None, key: sender.into() }.into()), - // Pay for execution. - BuyExecution { fees: xcm_fee, weight_limit: Unlimited }, // Transact on dest chain. Transact { origin_kind, require_weight_at_most: Weight::from_parts(weight_ref_time, weight_proof_size), call: payload.into(), }, + ExpectTransactStatus(MaybeErrorCode::Success), ] .into(); From a01aaaba8bd3b805dbf3f3d31ceed3b3914811ef Mon Sep 17 00:00:00 2001 From: ron Date: Tue, 13 Feb 2024 21:38:03 +0800 Subject: [PATCH 05/37] Update contract bindings --- relayer/contracts/gateway.go | 37 +++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/relayer/contracts/gateway.go b/relayer/contracts/gateway.go index 814a6a5017..e91becd0a0 100644 --- a/relayer/contracts/gateway.go +++ b/relayer/contracts/gateway.go @@ -47,6 +47,14 @@ type MultiAddress struct { Data []byte } +// TransactMessage is an auto generated low-level Go binding around an user-defined struct. +type TransactMessage struct { + OriginKind uint8 + Fee *big.Int + WeightAtMost Weight + Call []byte +} + // VerificationDigestItem is an auto generated low-level Go binding around an user-defined struct. type VerificationDigestItem struct { Kind *big.Int @@ -89,9 +97,15 @@ type VerificationProof struct { LeafProofOrder *big.Int } +// Weight is an auto generated low-level Go binding around an user-defined struct. +type Weight struct { + RefTime uint64 + ProofSize uint64 +} + // GatewayMetaData contains all meta data concerning the Gateway contract. var GatewayMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"function\",\"name\":\"agentOf\",\"inputs\":[{\"name\":\"agentID\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"channelNoncesOf\",\"inputs\":[{\"name\":\"channelID\",\"type\":\"bytes32\",\"internalType\":\"ChannelID\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"channelOperatingModeOf\",\"inputs\":[{\"name\":\"channelID\",\"type\":\"bytes32\",\"internalType\":\"ChannelID\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"enumOperatingMode\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"implementation\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isTokenRegistered\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"operatingMode\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"enumOperatingMode\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pricingParameters\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"UD60x18\"},{\"name\":\"\",\"type\":\"uint128\",\"internalType\":\"uint128\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"quoteRegisterTokenFee\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"quoteSendTokenFee\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"destinationChain\",\"type\":\"uint32\",\"internalType\":\"ParaID\"},{\"name\":\"destinationFee\",\"type\":\"uint128\",\"internalType\":\"uint128\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"registerToken\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"sendToken\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"destinationChain\",\"type\":\"uint32\",\"internalType\":\"ParaID\"},{\"name\":\"destinationAddress\",\"type\":\"tuple\",\"internalType\":\"structMultiAddress\",\"components\":[{\"name\":\"kind\",\"type\":\"uint8\",\"internalType\":\"enumKind\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"destinationFee\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"amount\",\"type\":\"uint128\",\"internalType\":\"uint128\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"submitV1\",\"inputs\":[{\"name\":\"message\",\"type\":\"tuple\",\"internalType\":\"structInboundMessage\",\"components\":[{\"name\":\"channelID\",\"type\":\"bytes32\",\"internalType\":\"ChannelID\"},{\"name\":\"nonce\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"command\",\"type\":\"uint8\",\"internalType\":\"enumCommand\"},{\"name\":\"params\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"maxDispatchGas\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"maxFeePerGas\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"reward\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"id\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"name\":\"leafProof\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"},{\"name\":\"headerProof\",\"type\":\"tuple\",\"internalType\":\"structVerification.Proof\",\"components\":[{\"name\":\"header\",\"type\":\"tuple\",\"internalType\":\"structVerification.ParachainHeader\",\"components\":[{\"name\":\"parentHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"number\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"stateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"extrinsicsRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"digestItems\",\"type\":\"tuple[]\",\"internalType\":\"structVerification.DigestItem[]\",\"components\":[{\"name\":\"kind\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"consensusEngineID\",\"type\":\"bytes4\",\"internalType\":\"bytes4\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}]},{\"name\":\"headProof\",\"type\":\"tuple\",\"internalType\":\"structVerification.HeadProof\",\"components\":[{\"name\":\"pos\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"width\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"proof\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"}]},{\"name\":\"leafPartial\",\"type\":\"tuple\",\"internalType\":\"structVerification.MMRLeafPartial\",\"components\":[{\"name\":\"version\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"parentNumber\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"parentHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"nextAuthoritySetID\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"nextAuthoritySetLen\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"nextAuthoritySetRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"name\":\"leafProof\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"},{\"name\":\"leafProofOrder\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"AgentCreated\",\"inputs\":[{\"name\":\"agentID\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"},{\"name\":\"agent\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"AgentFundsWithdrawn\",\"inputs\":[{\"name\":\"agentID\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"recipient\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ChannelCreated\",\"inputs\":[{\"name\":\"channelID\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"ChannelID\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ChannelUpdated\",\"inputs\":[{\"name\":\"channelID\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"ChannelID\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"InboundMessageDispatched\",\"inputs\":[{\"name\":\"channelID\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"ChannelID\"},{\"name\":\"nonce\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"},{\"name\":\"messageID\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"success\",\"type\":\"bool\",\"indexed\":false,\"internalType\":\"bool\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatingModeChanged\",\"inputs\":[{\"name\":\"mode\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"enumOperatingMode\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OutboundMessageAccepted\",\"inputs\":[{\"name\":\"channelID\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"ChannelID\"},{\"name\":\"nonce\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"},{\"name\":\"messageID\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"payload\",\"type\":\"bytes\",\"indexed\":false,\"internalType\":\"bytes\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PricingParametersChanged\",\"inputs\":[],\"anonymous\":false},{\"type\":\"event\",\"name\":\"TokenRegistrationSent\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"TokenSent\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"sender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"destinationChain\",\"type\":\"uint32\",\"indexed\":true,\"internalType\":\"ParaID\"},{\"name\":\"destinationAddress\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structMultiAddress\",\"components\":[{\"name\":\"kind\",\"type\":\"uint8\",\"internalType\":\"enumKind\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"amount\",\"type\":\"uint128\",\"indexed\":false,\"internalType\":\"uint128\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"TokenTransferFeesChanged\",\"inputs\":[],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Upgraded\",\"inputs\":[{\"name\":\"implementation\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false}]", + ABI: "[{\"type\":\"function\",\"name\":\"agentOf\",\"inputs\":[{\"name\":\"agentID\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"channelNoncesOf\",\"inputs\":[{\"name\":\"channelID\",\"type\":\"bytes32\",\"internalType\":\"ChannelID\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"channelOperatingModeOf\",\"inputs\":[{\"name\":\"channelID\",\"type\":\"bytes32\",\"internalType\":\"ChannelID\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"enumOperatingMode\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"implementation\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isTokenRegistered\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"operatingMode\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"enumOperatingMode\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pricingParameters\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"UD60x18\"},{\"name\":\"\",\"type\":\"uint128\",\"internalType\":\"uint128\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"quoteRegisterTokenFee\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"quoteSendTokenFee\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"destinationChain\",\"type\":\"uint32\",\"internalType\":\"ParaID\"},{\"name\":\"destinationFee\",\"type\":\"uint128\",\"internalType\":\"uint128\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"registerToken\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"sendToken\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"destinationChain\",\"type\":\"uint32\",\"internalType\":\"ParaID\"},{\"name\":\"destinationAddress\",\"type\":\"tuple\",\"internalType\":\"structMultiAddress\",\"components\":[{\"name\":\"kind\",\"type\":\"uint8\",\"internalType\":\"enumKind\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"destinationFee\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"amount\",\"type\":\"uint128\",\"internalType\":\"uint128\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"submitV1\",\"inputs\":[{\"name\":\"message\",\"type\":\"tuple\",\"internalType\":\"structInboundMessage\",\"components\":[{\"name\":\"channelID\",\"type\":\"bytes32\",\"internalType\":\"ChannelID\"},{\"name\":\"nonce\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"command\",\"type\":\"uint8\",\"internalType\":\"enumCommand\"},{\"name\":\"params\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"maxDispatchGas\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"maxFeePerGas\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"reward\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"id\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"name\":\"leafProof\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"},{\"name\":\"headerProof\",\"type\":\"tuple\",\"internalType\":\"structVerification.Proof\",\"components\":[{\"name\":\"header\",\"type\":\"tuple\",\"internalType\":\"structVerification.ParachainHeader\",\"components\":[{\"name\":\"parentHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"number\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"stateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"extrinsicsRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"digestItems\",\"type\":\"tuple[]\",\"internalType\":\"structVerification.DigestItem[]\",\"components\":[{\"name\":\"kind\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"consensusEngineID\",\"type\":\"bytes4\",\"internalType\":\"bytes4\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}]},{\"name\":\"headProof\",\"type\":\"tuple\",\"internalType\":\"structVerification.HeadProof\",\"components\":[{\"name\":\"pos\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"width\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"proof\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"}]},{\"name\":\"leafPartial\",\"type\":\"tuple\",\"internalType\":\"structVerification.MMRLeafPartial\",\"components\":[{\"name\":\"version\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"parentNumber\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"parentHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"nextAuthoritySetID\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"nextAuthoritySetLen\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"nextAuthoritySetRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"name\":\"leafProof\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"},{\"name\":\"leafProofOrder\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"transact\",\"inputs\":[{\"name\":\"destinationChain\",\"type\":\"uint32\",\"internalType\":\"ParaID\"},{\"name\":\"message\",\"type\":\"tuple\",\"internalType\":\"structTransactMessage\",\"components\":[{\"name\":\"originKind\",\"type\":\"uint8\",\"internalType\":\"enumOriginKind\"},{\"name\":\"fee\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"weightAtMost\",\"type\":\"tuple\",\"internalType\":\"structWeight\",\"components\":[{\"name\":\"refTime\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"proofSize\",\"type\":\"uint64\",\"internalType\":\"uint64\"}]},{\"name\":\"call\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"event\",\"name\":\"AgentCreated\",\"inputs\":[{\"name\":\"agentID\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"},{\"name\":\"agent\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"AgentFundsWithdrawn\",\"inputs\":[{\"name\":\"agentID\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"recipient\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ChannelCreated\",\"inputs\":[{\"name\":\"channelID\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"ChannelID\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ChannelUpdated\",\"inputs\":[{\"name\":\"channelID\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"ChannelID\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"InboundMessageDispatched\",\"inputs\":[{\"name\":\"channelID\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"ChannelID\"},{\"name\":\"nonce\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"},{\"name\":\"messageID\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"success\",\"type\":\"bool\",\"indexed\":false,\"internalType\":\"bool\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatingModeChanged\",\"inputs\":[{\"name\":\"mode\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"enumOperatingMode\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OutboundMessageAccepted\",\"inputs\":[{\"name\":\"channelID\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"ChannelID\"},{\"name\":\"nonce\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"},{\"name\":\"messageID\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"payload\",\"type\":\"bytes\",\"indexed\":false,\"internalType\":\"bytes\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PricingParametersChanged\",\"inputs\":[],\"anonymous\":false},{\"type\":\"event\",\"name\":\"TokenRegistrationSent\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"TokenSent\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"sender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"destinationChain\",\"type\":\"uint32\",\"indexed\":true,\"internalType\":\"ParaID\"},{\"name\":\"destinationAddress\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structMultiAddress\",\"components\":[{\"name\":\"kind\",\"type\":\"uint8\",\"internalType\":\"enumKind\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"amount\",\"type\":\"uint128\",\"indexed\":false,\"internalType\":\"uint128\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"TokenTransferFeesChanged\",\"inputs\":[],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Upgraded\",\"inputs\":[{\"name\":\"implementation\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false}]", } // GatewayABI is the input ABI used to generate the binding from. @@ -584,6 +598,27 @@ func (_Gateway *GatewayTransactorSession) SubmitV1(message InboundMessage, leafP return _Gateway.Contract.SubmitV1(&_Gateway.TransactOpts, message, leafProof, headerProof) } +// Transact is a paid mutator transaction binding the contract method 0xbb450536. +// +// Solidity: function transact(uint32 destinationChain, (uint8,uint128,(uint64,uint64),bytes) message) payable returns() +func (_Gateway *GatewayTransactor) Transact(opts *bind.TransactOpts, destinationChain uint32, message TransactMessage) (*types.Transaction, error) { + return _Gateway.contract.Transact(opts, "transact", destinationChain, message) +} + +// Transact is a paid mutator transaction binding the contract method 0xbb450536. +// +// Solidity: function transact(uint32 destinationChain, (uint8,uint128,(uint64,uint64),bytes) message) payable returns() +func (_Gateway *GatewaySession) Transact(destinationChain uint32, message TransactMessage) (*types.Transaction, error) { + return _Gateway.Contract.Transact(&_Gateway.TransactOpts, destinationChain, message) +} + +// Transact is a paid mutator transaction binding the contract method 0xbb450536. +// +// Solidity: function transact(uint32 destinationChain, (uint8,uint128,(uint64,uint64),bytes) message) payable returns() +func (_Gateway *GatewayTransactorSession) Transact(destinationChain uint32, message TransactMessage) (*types.Transaction, error) { + return _Gateway.Contract.Transact(&_Gateway.TransactOpts, destinationChain, message) +} + // GatewayAgentCreatedIterator is returned from FilterAgentCreated and is used to iterate over the raw logs and unpacked data for AgentCreated events raised by the Gateway contract. type GatewayAgentCreatedIterator struct { Event *GatewayAgentCreated // Event containing the contract specifics and raw log From b660ea85d0f2a1b9734f66391f5c44deb59a3dd0 Mon Sep 17 00:00:00 2001 From: ron Date: Tue, 13 Feb 2024 21:38:12 +0800 Subject: [PATCH 06/37] Update sdk --- polkadot-sdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polkadot-sdk b/polkadot-sdk index 348a1a0104..b2a828cc9a 160000 --- a/polkadot-sdk +++ b/polkadot-sdk @@ -1 +1 @@ -Subproject commit 348a1a010481002e41594ed75e5d78b7c2dbed92 +Subproject commit b2a828cc9acdc89be874efd2aaf15ad5cb727b5d From a94183af38d164039d3594a1ed46c20e0f430b8c Mon Sep 17 00:00:00 2001 From: ron Date: Wed, 14 Feb 2024 10:09:27 +0800 Subject: [PATCH 07/37] Remove unused --- polkadot-sdk~main | 1 - 1 file changed, 1 deletion(-) delete mode 120000 polkadot-sdk~main diff --git a/polkadot-sdk~main b/polkadot-sdk~main deleted file mode 120000 index c391b5a6de..0000000000 --- a/polkadot-sdk~main +++ /dev/null @@ -1 +0,0 @@ -../polkadot-sdk \ No newline at end of file From 7a110d375bdccb940c1ad39f9392fe2ee8f3e583 Mon Sep 17 00:00:00 2001 From: ron Date: Thu, 15 Feb 2024 13:56:07 +0800 Subject: [PATCH 08/37] Add smoke test --- .../tests/transact_from_eth_to_penpal.rs | 75 +++++++++++++++++++ web/packages/test/scripts/set-env.sh | 2 + 2 files changed, 77 insertions(+) create mode 100644 smoketest/tests/transact_from_eth_to_penpal.rs diff --git a/smoketest/tests/transact_from_eth_to_penpal.rs b/smoketest/tests/transact_from_eth_to_penpal.rs new file mode 100644 index 0000000000..d34ee9c29a --- /dev/null +++ b/smoketest/tests/transact_from_eth_to_penpal.rs @@ -0,0 +1,75 @@ +use ethers::{core::types::Address, types::Bytes}; +use futures::StreamExt; +use hex_literal::hex; +use snowbridge_smoketest::{ + constants::*, + contracts::{gateway_upgrade_mock::TransactMessage, i_gateway, shared_types::Weight}, + helper::{initial_clients, print_event_log_for_unit_tests}, + parachains::penpal::api::system::events::Remarked, +}; + +#[tokio::test] +async fn transact_from_eth_to_penpal() { + let test_clients = initial_clients().await.expect("initialize clients"); + let ethereum_client = *(test_clients.ethereum_signed_client.clone()); + let penpal_client = *(test_clients.penpal_client.clone()); + + let gateway_addr: Address = GATEWAY_PROXY_CONTRACT.into(); + let gateway = i_gateway::IGateway::new(gateway_addr, ethereum_client.clone()); + + let message = TransactMessage { + origin_kind: 0, + fee: 40_000_000_000, + weight_at_most: Weight { ref_time: 40_000_000, proof_size: 8_000 }, + //system.remark + call: Bytes::from(hex!("00071468656c6c6f").to_vec()), + }; + let fee = gateway.quote_register_token_fee().call().await.unwrap(); + + let receipt = gateway + .transact(PENPAL_PARA_ID, message) + .value(fee) + .send() + .await + .unwrap() + .await + .unwrap() + .unwrap(); + + println!( + "receipt transaction hash: {:#?}, transaction block: {:#?}", + hex::encode(receipt.transaction_hash), + receipt.block_number + ); + + // Log for OutboundMessageAccepted + let outbound_message_accepted_log = receipt.logs.last().unwrap(); + + // print log for unit tests + print_event_log_for_unit_tests(outbound_message_accepted_log); + + assert_eq!(receipt.status.unwrap().as_u64(), 1u64); + + let wait_for_blocks = 50; + let mut blocks = penpal_client + .blocks() + .subscribe_finalized() + .await + .expect("block subscription") + .take(wait_for_blocks); + + let mut event_found = false; + while let Some(Ok(block)) = blocks.next().await { + println!("Polling penpal block {} for system remark event.", block.number()); + + let events = block.events().await.unwrap(); + for _ in events.find::() { + println!("Remarked event found in penpal block {}.", block.number()); + event_found = true; + } + if event_found { + break + } + } + assert!(event_found) +} diff --git a/web/packages/test/scripts/set-env.sh b/web/packages/test/scripts/set-env.sh index 2291d2b6eb..201420bdca 100755 --- a/web/packages/test/scripts/set-env.sh +++ b/web/packages/test/scripts/set-env.sh @@ -62,6 +62,8 @@ reset_ethereum="${RESET_ETHEREUM:-true}" ## Important accounts # Useful tool to get these account values: https://www.shawntabrizi.com/substrate-js-utilities/ +# Account for bridgehub (Sibling parachain 1013 in testnet) +bridgehub_sovereign_account="${BRIDGEHUB_SOVEREIGN_ACCOUNT:-0x7369626cf5030000000000000000000000000000000000000000000000000000}" # Account for assethub (Sibling parachain 1000 5Eg2fntNprdN3FgH4sfEaaZhYtddZQSQUqvYJ1f2mLtinVhV in testnet) assethub_sovereign_account="${ASSETHUB_SOVEREIGN_ACCOUNT:-0x7369626ce8030000000000000000000000000000000000000000000000000000}" # Account for penpal (Sibling parachain 2000 5Eg2fntJ27qsari4FGrGhrMqKFDRnkNSR6UshkZYBGXmSuC8 in testnet) From b57f0c155530c965fe787dbf0e1650c352f984cd Mon Sep 17 00:00:00 2001 From: ron Date: Thu, 15 Feb 2024 15:14:42 +0800 Subject: [PATCH 09/37] Improve smoke test --- .../tests/transact_from_eth_to_penpal.rs | 5 ++--- web/packages/test/scripts/configure-penpal.sh | 20 +++++++++++++++++++ web/packages/test/scripts/set-env.sh | 2 +- web/packages/test/scripts/start-services.sh | 7 ++++++- 4 files changed, 29 insertions(+), 5 deletions(-) create mode 100755 web/packages/test/scripts/configure-penpal.sh diff --git a/smoketest/tests/transact_from_eth_to_penpal.rs b/smoketest/tests/transact_from_eth_to_penpal.rs index d34ee9c29a..3d46176abd 100644 --- a/smoketest/tests/transact_from_eth_to_penpal.rs +++ b/smoketest/tests/transact_from_eth_to_penpal.rs @@ -1,4 +1,4 @@ -use ethers::{core::types::Address, types::Bytes}; +use ethers::{core::types::Address, prelude::U256, types::Bytes}; use futures::StreamExt; use hex_literal::hex; use snowbridge_smoketest::{ @@ -24,11 +24,10 @@ async fn transact_from_eth_to_penpal() { //system.remark call: Bytes::from(hex!("00071468656c6c6f").to_vec()), }; - let fee = gateway.quote_register_token_fee().call().await.unwrap(); let receipt = gateway .transact(PENPAL_PARA_ID, message) - .value(fee) + .value::(100_000_000_000_000_000_u128.into()) .send() .await .unwrap() diff --git a/web/packages/test/scripts/configure-penpal.sh b/web/packages/test/scripts/configure-penpal.sh new file mode 100755 index 0000000000..4ebed29e2e --- /dev/null +++ b/web/packages/test/scripts/configure-penpal.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -eu + +source scripts/set-env.sh +source scripts/xcm-helper.sh + +fund_bridgehub_sovereign() { + local call="0x0a08007369626cf5030000000000000000000000000000000000000000000000000000070010a5d4e8" + send_governance_transact_from_relaychain $PENPAL_PARAID "$call" +} + +configure_penpal() { + fund_bridgehub_sovereign +} + +if [ -z "${from_start_services:-}" ]; then + echo "config penpal only!" + configure_penpal + wait +fi diff --git a/web/packages/test/scripts/set-env.sh b/web/packages/test/scripts/set-env.sh index 201420bdca..5fbaf0be19 100755 --- a/web/packages/test/scripts/set-env.sh +++ b/web/packages/test/scripts/set-env.sh @@ -44,11 +44,11 @@ assethub_ws_url="${ASSET_HUB_WS_URL:-ws://127.0.0.1:12144}" assethub_seed="${ASSET_HUB_SEED:-//Alice}" export ASSET_HUB_PARAID="${ASSET_HUB_PARAID:-1000}" export ASSET_HUB_AGENT_ID="${ASSET_HUB_AGENT_ID:-0x81c5ab2571199e3188135178f3c2c8e2d268be1313d029b30f534fa579b69b79}" - export ASSET_HUB_CHANNEL_ID="0xc173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539" export PENPAL_CHANNEL_ID="0xa69fbbae90bb6096d59b1930bbcfc8a3ef23959d226b1861deb7ad8fb06c6fa3" export PRIMARY_GOVERNANCE_CHANNEL_ID="0x0000000000000000000000000000000000000000000000000000000000000001" export SECONDARY_GOVERNANCE_CHANNEL_ID="0x0000000000000000000000000000000000000000000000000000000000000002" +export PENPAL_PARAID="${PENPAL_PARAID:-2000}" # Token decimal of the relaychain(KSM|ROC:12,DOT:10) export FOREIGN_TOKEN_DECIMALS=12 diff --git a/web/packages/test/scripts/start-services.sh b/web/packages/test/scripts/start-services.sh index 9b5f9c697a..4399601a6f 100755 --- a/web/packages/test/scripts/start-services.sh +++ b/web/packages/test/scripts/start-services.sh @@ -51,8 +51,13 @@ echo "Config assethub" source scripts/configure-assethub.sh configure_assethub +# 8. config penpal +echo "Config penpal" +source scripts/configure-penpal.sh +configure_penpal + if [ "$skip_relayer" == "false" ]; then - # 8. start relayer + # 9. start relayer echo "Starting relayers" source scripts/start-relayer.sh deploy_relayer From 3ad5b7d18a451280a23ddd1ef2663a3c5c8ec522 Mon Sep 17 00:00:00 2001 From: ron Date: Thu, 15 Feb 2024 15:27:07 +0800 Subject: [PATCH 10/37] Add polkadot-sdk as soft link --- polkadot-sdk | 1 + 1 file changed, 1 insertion(+) create mode 120000 polkadot-sdk diff --git a/polkadot-sdk b/polkadot-sdk new file mode 120000 index 0000000000..c391b5a6de --- /dev/null +++ b/polkadot-sdk @@ -0,0 +1 @@ +../polkadot-sdk \ No newline at end of file From e93c72592cb6988361f474e8005bfaf49f9a42b0 Mon Sep 17 00:00:00 2001 From: ron Date: Thu, 15 Feb 2024 15:28:33 +0800 Subject: [PATCH 11/37] Revert typos config --- _typos.toml | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/_typos.toml b/_typos.toml index 55e956b495..c687a5ce1a 100644 --- a/_typos.toml +++ b/_typos.toml @@ -7,11 +7,22 @@ extend-exclude = [ "**/*ffi*.js", "**/*mock*.rs", "**/*data*.rs", - "polkadot-sdk/**", + "polkadot-sdk/bridges/bin", + "polkadot-sdk/bridges/docs", + "polkadot-sdk/bridges/modules", + "polkadot-sdk/bridges/primitives", + "polkadot-sdk/bridges/scripts", + "polkadot-sdk/bridges/zombienet", + "polkadot-sdk/cumulus", + "polkadot-sdk/docker", + "polkadot-sdk/docs", + "polkadot-sdk/polkadot", + "polkadot-sdk/prdoc", + "polkadot-sdk/scripts", + "polkadot-sdk/substrate", "smoketest/src/parachains", "smoketest/src/contracts", "lodestar/**", "go-ethereum/**", "go.work.sum", - "parachain/Cargo.toml", ] From 65714ef836e37071050dfd02c48621063a302a90 Mon Sep 17 00:00:00 2001 From: ron Date: Fri, 16 Feb 2024 20:19:23 +0800 Subject: [PATCH 12/37] Add valid check --- contracts/src/Gateway.sol | 3 +++ contracts/src/Types.sol | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/contracts/src/Gateway.sol b/contracts/src/Gateway.sol index d9fc6bcd27..eb9cdb75cc 100644 --- a/contracts/src/Gateway.sol +++ b/contracts/src/Gateway.sol @@ -624,6 +624,9 @@ contract Gateway is IGateway, IInitializable { /// @inheritdoc IGateway function transact(ParaID destinationChain, TransactMessage calldata message) external payable { + if (message.validate() == false) { + revert InvalidTransact(); + } Ticket memory ticket; Costs memory costs; costs.foreign = message.fee; diff --git a/contracts/src/Types.sol b/contracts/src/Types.sol index 8f6ab119d1..6ecad6431f 100644 --- a/contracts/src/Types.sol +++ b/contracts/src/Types.sol @@ -132,9 +132,21 @@ function encode(OriginKind kind) pure returns (bytes1 result) { return result; } +using {validate} for TransactMessage global; + struct TransactMessage { OriginKind originKind; uint128 fee; Weight weightAtMost; bytes call; } + +function validate(TransactMessage calldata message) pure returns (bool) { + if ( + message.call.length == 0 || message.fee == 0 || message.weightAtMost.refTime == 0 + || message.weightAtMost.proofSize == 0 + ) { + return false; + } + return true; +} From 4719a4252a3409d2cd629ce7adb6299c6581c245 Mon Sep 17 00:00:00 2001 From: ron Date: Mon, 19 Feb 2024 23:52:48 +0800 Subject: [PATCH 13/37] Remove TransactMessage and inline the params --- contracts/src/Gateway.sol | 20 ++++++++++++-------- contracts/src/SubstrateTypes.sol | 2 +- contracts/src/Types.sol | 19 ------------------- contracts/src/interfaces/IGateway.sol | 10 ++++++++-- contracts/test/Gateway.t.sol | 13 ++++++------- contracts/test/mocks/GatewayUpgradeMock.sol | 11 +++++++++-- 6 files changed, 36 insertions(+), 39 deletions(-) diff --git a/contracts/src/Gateway.sol b/contracts/src/Gateway.sol index eb9cdb75cc..4b5c9d917a 100644 --- a/contracts/src/Gateway.sol +++ b/contracts/src/Gateway.sol @@ -18,8 +18,8 @@ import { MultiAddress, Ticket, Costs, - TransactMessage, - OriginKind + OriginKind, + Weight } from "./Types.sol"; import {IGateway} from "./interfaces/IGateway.sol"; import {IInitializable} from "./interfaces/IInitializable.sol"; @@ -623,16 +623,20 @@ contract Gateway is IGateway, IInitializable { } /// @inheritdoc IGateway - function transact(ParaID destinationChain, TransactMessage calldata message) external payable { - if (message.validate() == false) { + function transact( + ParaID destinationChain, + OriginKind originKind, + uint128 fee, + Weight calldata weightAtMost, + bytes calldata call + ) external payable { + if (call.length == 0 || fee == 0 || weightAtMost.refTime == 0 || weightAtMost.proofSize == 0) { revert InvalidTransact(); } Ticket memory ticket; Costs memory costs; - costs.foreign = message.fee; - bytes memory payload = SubstrateTypes.Transact( - msg.sender, message.originKind.encode(), message.fee, message.weightAtMost, message.call - ); + costs.foreign = fee; + bytes memory payload = SubstrateTypes.Transact(msg.sender, originKind.encode(), fee, weightAtMost, call); ticket.dest = destinationChain; ticket.costs = costs; ticket.payload = payload; diff --git a/contracts/src/SubstrateTypes.sol b/contracts/src/SubstrateTypes.sol index 982f1ffab0..3b276f0012 100644 --- a/contracts/src/SubstrateTypes.sol +++ b/contracts/src/SubstrateTypes.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.23; import {ScaleCodec} from "./utils/ScaleCodec.sol"; -import {ParaID, TransactMessage, Weight, OriginKind} from "./Types.sol"; +import {ParaID, Weight, OriginKind} from "./Types.sol"; /** * @title SCALE encoders for common Substrate types diff --git a/contracts/src/Types.sol b/contracts/src/Types.sol index 6ecad6431f..6c782e3c6e 100644 --- a/contracts/src/Types.sol +++ b/contracts/src/Types.sol @@ -131,22 +131,3 @@ function encode(OriginKind kind) pure returns (bytes1 result) { } return result; } - -using {validate} for TransactMessage global; - -struct TransactMessage { - OriginKind originKind; - uint128 fee; - Weight weightAtMost; - bytes call; -} - -function validate(TransactMessage calldata message) pure returns (bool) { - if ( - message.call.length == 0 || message.fee == 0 || message.weightAtMost.refTime == 0 - || message.weightAtMost.proofSize == 0 - ) { - return false; - } - return true; -} diff --git a/contracts/src/interfaces/IGateway.sol b/contracts/src/interfaces/IGateway.sol index 51e9eece35..ebdf46fca7 100644 --- a/contracts/src/interfaces/IGateway.sol +++ b/contracts/src/interfaces/IGateway.sol @@ -2,7 +2,7 @@ // SPDX-FileCopyrightText: 2023 Snowfork pragma solidity 0.8.23; -import {OperatingMode, InboundMessage, ParaID, ChannelID, MultiAddress, TransactMessage} from "../Types.sol"; +import {OperatingMode, InboundMessage, ParaID, ChannelID, MultiAddress, OriginKind, Weight} from "../Types.sol"; import {Verification} from "../Verification.sol"; import {UD60x18} from "prb/math/src/UD60x18.sol"; @@ -107,5 +107,11 @@ interface IGateway { ) external payable; /// @dev Call transact in destinationChain - function transact(ParaID destinationChain, TransactMessage calldata message) external payable; + function transact( + ParaID destinationChain, + OriginKind originKind, + uint128 fee, + Weight calldata weightAtMost, + bytes calldata call + ) external payable; } diff --git a/contracts/test/Gateway.t.sol b/contracts/test/Gateway.t.sol index 7d6dcafd63..5b7b645fcd 100644 --- a/contracts/test/Gateway.t.sol +++ b/contracts/test/Gateway.t.sol @@ -43,7 +43,6 @@ import { Command, multiAddressFromBytes32, multiAddressFromBytes20, - TransactMessage, Weight, OriginKind } from "../src/Types.sol"; @@ -844,22 +843,22 @@ contract GatewayTest is Test { * Transact */ function testTransactFromXcmOrigin() public { - TransactMessage memory message = TransactMessage(OriginKind.Xcm, 1, Weight(1, 1), bytes("0x1")); - bytes memory payload = SubstrateTypes.Transact(account1, 0x03, message.fee, message.weightAtMost, message.call); + bytes memory payload = SubstrateTypes.Transact(account1, 0x03, 1, Weight(1, 1), bytes("0x1")); console.logBytes(payload); vm.expectEmit(true, false, false, true); emit IGateway.OutboundMessageAccepted(penpalParaID.into(), 1, messageID, payload); hoax(address(account1)); - IGateway(address(gateway)).transact{value: 1 ether}(penpalParaID, message); + IGateway(address(gateway)).transact{value: 1 ether}(penpalParaID, OriginKind.Xcm, 1, Weight(1, 1), bytes("0x1")); } function testTransactFromSignedOrigin() public { - TransactMessage memory message = TransactMessage(OriginKind.SovereignAccount, 1, Weight(1, 1), bytes("0x1")); - bytes memory payload = SubstrateTypes.Transact(account1, 0x01, message.fee, message.weightAtMost, message.call); + bytes memory payload = SubstrateTypes.Transact(account1, 0x01, 1, Weight(1, 1), bytes("0x1")); console.logBytes(payload); vm.expectEmit(true, false, false, true); emit IGateway.OutboundMessageAccepted(penpalParaID.into(), 1, messageID, payload); hoax(address(account1)); - IGateway(address(gateway)).transact{value: 1 ether}(penpalParaID, message); + IGateway(address(gateway)).transact{value: 1 ether}( + penpalParaID, OriginKind.SovereignAccount, 1, Weight(1, 1), bytes("0x1") + ); } } diff --git a/contracts/test/mocks/GatewayUpgradeMock.sol b/contracts/test/mocks/GatewayUpgradeMock.sol index 800fa85fca..ea6d755c7f 100644 --- a/contracts/test/mocks/GatewayUpgradeMock.sol +++ b/contracts/test/mocks/GatewayUpgradeMock.sol @@ -10,7 +10,8 @@ import { Command, ChannelID, MultiAddress, - TransactMessage + OriginKind, + Weight } from "../../src/Types.sol"; import {IGateway} from "../../src/interfaces/IGateway.sol"; import {IInitializable} from "../../src/interfaces/IInitializable.sol"; @@ -71,5 +72,11 @@ contract GatewayUpgradeMock is IGateway, IInitializable { return (convert(0), uint128(0)); } - function transact(ParaID destinationChain, TransactMessage calldata message) external payable {} + function transact( + ParaID destinationChain, + OriginKind originKind, + uint128 fee, + Weight calldata weightAtMost, + bytes calldata call + ) external payable {} } From a78b1f938f318a8897a4ba36e636e91e516316d0 Mon Sep 17 00:00:00 2001 From: ron Date: Mon, 19 Feb 2024 23:56:12 +0800 Subject: [PATCH 14/37] Remove from .gitignore --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 27b5a17f9e..9e3c9ed722 100644 --- a/.gitignore +++ b/.gitignore @@ -30,4 +30,3 @@ contracts/beefy-state.json go/ gocache/ -/parachain From c192361a3bd28513f381d683f13192773b9fe6ad Mon Sep 17 00:00:00 2001 From: ron Date: Tue, 20 Feb 2024 00:09:59 +0800 Subject: [PATCH 15/37] Add quoteTransactFee --- contracts/src/Gateway.sol | 7 ++++++- contracts/src/interfaces/IGateway.sol | 3 +++ contracts/test/mocks/GatewayUpgradeMock.sol | 4 ++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/contracts/src/Gateway.sol b/contracts/src/Gateway.sol index 4b5c9d917a..6cb067259b 100644 --- a/contracts/src/Gateway.sol +++ b/contracts/src/Gateway.sol @@ -635,11 +635,16 @@ contract Gateway is IGateway, IInitializable { } Ticket memory ticket; Costs memory costs; - costs.foreign = fee; bytes memory payload = SubstrateTypes.Transact(msg.sender, originKind.encode(), fee, weightAtMost, call); ticket.dest = destinationChain; ticket.costs = costs; ticket.payload = payload; _submitOutbound(ticket); } + + /// @inheritdoc IGateway + function quoteTransactFee() external view returns (uint256) { + PricingStorage.Layout storage pricing = PricingStorage.layout(); + return _convertToNative(pricing.exchangeRate, pricing.deliveryCost); + } } diff --git a/contracts/src/interfaces/IGateway.sol b/contracts/src/interfaces/IGateway.sol index ebdf46fca7..4775cccc1b 100644 --- a/contracts/src/interfaces/IGateway.sol +++ b/contracts/src/interfaces/IGateway.sol @@ -114,4 +114,7 @@ interface IGateway { Weight calldata weightAtMost, bytes calldata call ) external payable; + + /// @dev Quote a fee in Ether for transact + function quoteTransactFee() external view returns (uint256); } diff --git a/contracts/test/mocks/GatewayUpgradeMock.sol b/contracts/test/mocks/GatewayUpgradeMock.sol index ea6d755c7f..322283e420 100644 --- a/contracts/test/mocks/GatewayUpgradeMock.sol +++ b/contracts/test/mocks/GatewayUpgradeMock.sol @@ -79,4 +79,8 @@ contract GatewayUpgradeMock is IGateway, IInitializable { Weight calldata weightAtMost, bytes calldata call ) external payable {} + + function quoteTransactFee() external pure returns (uint256) { + return 1; + } } From acf2362f472bf1356d11e5974bd2abf7c6095098 Mon Sep 17 00:00:00 2001 From: ron Date: Tue, 20 Feb 2024 09:10:14 +0800 Subject: [PATCH 16/37] Rename to destinationFee --- contracts/src/Gateway.sol | 7 ++++--- contracts/src/interfaces/IGateway.sol | 2 +- contracts/test/mocks/GatewayUpgradeMock.sol | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/contracts/src/Gateway.sol b/contracts/src/Gateway.sol index 6cb067259b..e50f31d8e5 100644 --- a/contracts/src/Gateway.sol +++ b/contracts/src/Gateway.sol @@ -626,16 +626,17 @@ contract Gateway is IGateway, IInitializable { function transact( ParaID destinationChain, OriginKind originKind, - uint128 fee, + uint128 destinationFee, Weight calldata weightAtMost, bytes calldata call ) external payable { - if (call.length == 0 || fee == 0 || weightAtMost.refTime == 0 || weightAtMost.proofSize == 0) { + if (call.length == 0 || destinationFee == 0 || weightAtMost.refTime == 0 || weightAtMost.proofSize == 0) { revert InvalidTransact(); } Ticket memory ticket; Costs memory costs; - bytes memory payload = SubstrateTypes.Transact(msg.sender, originKind.encode(), fee, weightAtMost, call); + bytes memory payload = + SubstrateTypes.Transact(msg.sender, originKind.encode(), destinationFee, weightAtMost, call); ticket.dest = destinationChain; ticket.costs = costs; ticket.payload = payload; diff --git a/contracts/src/interfaces/IGateway.sol b/contracts/src/interfaces/IGateway.sol index 4775cccc1b..44b420be9f 100644 --- a/contracts/src/interfaces/IGateway.sol +++ b/contracts/src/interfaces/IGateway.sol @@ -110,7 +110,7 @@ interface IGateway { function transact( ParaID destinationChain, OriginKind originKind, - uint128 fee, + uint128 destinationFee, Weight calldata weightAtMost, bytes calldata call ) external payable; diff --git a/contracts/test/mocks/GatewayUpgradeMock.sol b/contracts/test/mocks/GatewayUpgradeMock.sol index 322283e420..08c4be6324 100644 --- a/contracts/test/mocks/GatewayUpgradeMock.sol +++ b/contracts/test/mocks/GatewayUpgradeMock.sol @@ -75,7 +75,7 @@ contract GatewayUpgradeMock is IGateway, IInitializable { function transact( ParaID destinationChain, OriginKind originKind, - uint128 fee, + uint128 destinationFee, Weight calldata weightAtMost, bytes calldata call ) external payable {} From 207460deb0e779d7e142358f054c7e508a195413 Mon Sep 17 00:00:00 2001 From: ron Date: Tue, 20 Feb 2024 09:47:51 +0800 Subject: [PATCH 17/37] Test quoteTransactFee --- contracts/test/Gateway.t.sol | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/contracts/test/Gateway.t.sol b/contracts/test/Gateway.t.sol index 5b7b645fcd..164a38ab88 100644 --- a/contracts/test/Gateway.t.sol +++ b/contracts/test/Gateway.t.sol @@ -851,7 +851,7 @@ contract GatewayTest is Test { IGateway(address(gateway)).transact{value: 1 ether}(penpalParaID, OriginKind.Xcm, 1, Weight(1, 1), bytes("0x1")); } - function testTransactFromSignedOrigin() public { + function testTransactFromSovereignAccount() public { bytes memory payload = SubstrateTypes.Transact(account1, 0x01, 1, Weight(1, 1), bytes("0x1")); console.logBytes(payload); vm.expectEmit(true, false, false, true); @@ -861,4 +861,17 @@ contract GatewayTest is Test { penpalParaID, OriginKind.SovereignAccount, 1, Weight(1, 1), bytes("0x1") ); } + + function testTransactFromSovereignAccountWithFee() public { + bytes memory payload = SubstrateTypes.Transact(account1, 0x01, 1, Weight(1, 1), bytes("0x1")); + console.logBytes(payload); + uint256 fee = IGateway(address(gateway)).quoteTransactFee(); + assertEq(fee, 2500000000000000); + vm.expectEmit(true, false, false, true); + emit IGateway.OutboundMessageAccepted(penpalParaID.into(), 1, messageID, payload); + hoax(address(account1)); + IGateway(address(gateway)).transact{value: fee}( + penpalParaID, OriginKind.SovereignAccount, 1, Weight(1, 1), bytes("0x1") + ); + } } From f8f0f57b29aae65c48ae0fe4fb577fe8cd67ac68 Mon Sep 17 00:00:00 2001 From: ron Date: Thu, 22 Feb 2024 10:41:51 +0800 Subject: [PATCH 18/37] Check call length --- contracts/src/Gateway.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/src/Gateway.sol b/contracts/src/Gateway.sol index e50f31d8e5..9a3e90cd3f 100644 --- a/contracts/src/Gateway.sol +++ b/contracts/src/Gateway.sol @@ -630,7 +630,7 @@ contract Gateway is IGateway, IInitializable { Weight calldata weightAtMost, bytes calldata call ) external payable { - if (call.length == 0 || destinationFee == 0 || weightAtMost.refTime == 0 || weightAtMost.proofSize == 0) { + if (call.length < 2 || destinationFee == 0 || weightAtMost.refTime == 0 || weightAtMost.proofSize == 0) { revert InvalidTransact(); } Ticket memory ticket; From 00abc1330b4eb6e0932ddbc7e8d1bbe1ca757eae Mon Sep 17 00:00:00 2001 From: ron Date: Thu, 22 Feb 2024 20:50:46 +0800 Subject: [PATCH 19/37] Initialize ticket with explicit cost --- contracts/src/Gateway.sol | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/contracts/src/Gateway.sol b/contracts/src/Gateway.sol index 9a3e90cd3f..21053340d0 100644 --- a/contracts/src/Gateway.sol +++ b/contracts/src/Gateway.sol @@ -630,16 +630,9 @@ contract Gateway is IGateway, IInitializable { Weight calldata weightAtMost, bytes calldata call ) external payable { - if (call.length < 2 || destinationFee == 0 || weightAtMost.refTime == 0 || weightAtMost.proofSize == 0) { - revert InvalidTransact(); - } - Ticket memory ticket; - Costs memory costs; bytes memory payload = SubstrateTypes.Transact(msg.sender, originKind.encode(), destinationFee, weightAtMost, call); - ticket.dest = destinationChain; - ticket.costs = costs; - ticket.payload = payload; + Ticket memory ticket = Ticket({dest: destinationChain, costs: Costs({native: 0, foreign: 0}), payload: payload}); _submitOutbound(ticket); } From 5084432d3b8c46ad002216bc34f0d94c8ca4dc08 Mon Sep 17 00:00:00 2001 From: ron Date: Thu, 22 Feb 2024 20:57:32 +0800 Subject: [PATCH 20/37] Rename to sendCall --- contracts/src/Gateway.sol | 4 ++-- contracts/src/interfaces/IGateway.sol | 4 ++-- contracts/test/Gateway.t.sol | 8 ++++---- contracts/test/mocks/GatewayUpgradeMock.sol | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/contracts/src/Gateway.sol b/contracts/src/Gateway.sol index 21053340d0..990b42807b 100644 --- a/contracts/src/Gateway.sol +++ b/contracts/src/Gateway.sol @@ -623,7 +623,7 @@ contract Gateway is IGateway, IInitializable { } /// @inheritdoc IGateway - function transact( + function sendCall( ParaID destinationChain, OriginKind originKind, uint128 destinationFee, @@ -637,7 +637,7 @@ contract Gateway is IGateway, IInitializable { } /// @inheritdoc IGateway - function quoteTransactFee() external view returns (uint256) { + function quoteSendCallFee() external view returns (uint256) { PricingStorage.Layout storage pricing = PricingStorage.layout(); return _convertToNative(pricing.exchangeRate, pricing.deliveryCost); } diff --git a/contracts/src/interfaces/IGateway.sol b/contracts/src/interfaces/IGateway.sol index 44b420be9f..de11a39956 100644 --- a/contracts/src/interfaces/IGateway.sol +++ b/contracts/src/interfaces/IGateway.sol @@ -107,7 +107,7 @@ interface IGateway { ) external payable; /// @dev Call transact in destinationChain - function transact( + function sendCall( ParaID destinationChain, OriginKind originKind, uint128 destinationFee, @@ -116,5 +116,5 @@ interface IGateway { ) external payable; /// @dev Quote a fee in Ether for transact - function quoteTransactFee() external view returns (uint256); + function quoteSendCallFee() external view returns (uint256); } diff --git a/contracts/test/Gateway.t.sol b/contracts/test/Gateway.t.sol index 164a38ab88..9b7659232e 100644 --- a/contracts/test/Gateway.t.sol +++ b/contracts/test/Gateway.t.sol @@ -848,7 +848,7 @@ contract GatewayTest is Test { vm.expectEmit(true, false, false, true); emit IGateway.OutboundMessageAccepted(penpalParaID.into(), 1, messageID, payload); hoax(address(account1)); - IGateway(address(gateway)).transact{value: 1 ether}(penpalParaID, OriginKind.Xcm, 1, Weight(1, 1), bytes("0x1")); + IGateway(address(gateway)).sendCall{value: 1 ether}(penpalParaID, OriginKind.Xcm, 1, Weight(1, 1), bytes("0x1")); } function testTransactFromSovereignAccount() public { @@ -857,7 +857,7 @@ contract GatewayTest is Test { vm.expectEmit(true, false, false, true); emit IGateway.OutboundMessageAccepted(penpalParaID.into(), 1, messageID, payload); hoax(address(account1)); - IGateway(address(gateway)).transact{value: 1 ether}( + IGateway(address(gateway)).sendCall{value: 1 ether}( penpalParaID, OriginKind.SovereignAccount, 1, Weight(1, 1), bytes("0x1") ); } @@ -865,12 +865,12 @@ contract GatewayTest is Test { function testTransactFromSovereignAccountWithFee() public { bytes memory payload = SubstrateTypes.Transact(account1, 0x01, 1, Weight(1, 1), bytes("0x1")); console.logBytes(payload); - uint256 fee = IGateway(address(gateway)).quoteTransactFee(); + uint256 fee = IGateway(address(gateway)).quoteSendCallFee(); assertEq(fee, 2500000000000000); vm.expectEmit(true, false, false, true); emit IGateway.OutboundMessageAccepted(penpalParaID.into(), 1, messageID, payload); hoax(address(account1)); - IGateway(address(gateway)).transact{value: fee}( + IGateway(address(gateway)).sendCall{value: fee}( penpalParaID, OriginKind.SovereignAccount, 1, Weight(1, 1), bytes("0x1") ); } diff --git a/contracts/test/mocks/GatewayUpgradeMock.sol b/contracts/test/mocks/GatewayUpgradeMock.sol index 08c4be6324..ddf6d545c5 100644 --- a/contracts/test/mocks/GatewayUpgradeMock.sol +++ b/contracts/test/mocks/GatewayUpgradeMock.sol @@ -72,7 +72,7 @@ contract GatewayUpgradeMock is IGateway, IInitializable { return (convert(0), uint128(0)); } - function transact( + function sendCall( ParaID destinationChain, OriginKind originKind, uint128 destinationFee, @@ -80,7 +80,7 @@ contract GatewayUpgradeMock is IGateway, IInitializable { bytes calldata call ) external payable {} - function quoteTransactFee() external pure returns (uint256) { + function quoteSendCallFee() external pure returns (uint256) { return 1; } } From d7cc7d84860b19f54653d2e44301b6de08ee25f1 Mon Sep 17 00:00:00 2001 From: ron Date: Fri, 23 Feb 2024 12:32:24 +0800 Subject: [PATCH 21/37] Reuse weight type with compact u64 encode support --- contracts/src/SubstrateTypes.sol | 4 +- contracts/src/utils/Math.sol | 14 ++++ contracts/src/utils/ScaleCodec.sol | 20 +++++ contracts/test/ScaleCodec.t.sol | 12 +++ relayer/contracts/gateway.go | 83 ++++++++++++------- .../tests/transact_from_eth_to_penpal.rs | 18 ++-- 6 files changed, 109 insertions(+), 42 deletions(-) diff --git a/contracts/src/SubstrateTypes.sol b/contracts/src/SubstrateTypes.sol index 3b276f0012..43d1b835f8 100644 --- a/contracts/src/SubstrateTypes.sol +++ b/contracts/src/SubstrateTypes.sol @@ -147,8 +147,8 @@ library SubstrateTypes { SubstrateTypes.H160(sender), originKind, ScaleCodec.encodeU128(fee), - ScaleCodec.encodeU64(weight.refTime), - ScaleCodec.encodeU64(weight.proofSize), + ScaleCodec.encodeCompactU64(weight.refTime), + ScaleCodec.encodeCompactU64(weight.proofSize), ScaleCodec.checkedEncodeCompactU32(call.length), call ); diff --git a/contracts/src/utils/Math.sol b/contracts/src/utils/Math.sol index ba0036dab9..5ab529d0e3 100644 --- a/contracts/src/utils/Math.sol +++ b/contracts/src/utils/Math.sol @@ -114,4 +114,18 @@ library Math { return a - b; } } + + /** + * @dev Return the count of leading zeros of the uint64 value + */ + function leadingZeros(uint64 val) internal pure returns (uint8) { + unchecked { + uint8 num = 0; + while (val > 0) { + val = val >> 1; + num++; + } + return 64 - num; + } + } } diff --git a/contracts/src/utils/ScaleCodec.sol b/contracts/src/utils/ScaleCodec.sol index a0d96bb06b..4b54de17be 100644 --- a/contracts/src/utils/ScaleCodec.sol +++ b/contracts/src/utils/ScaleCodec.sol @@ -2,7 +2,11 @@ // SPDX-FileCopyrightText: 2023 Snowfork pragma solidity 0.8.23; +import {Math} from "./Math.sol"; + library ScaleCodec { + using Math for uint64; + error UnsupportedCompactEncoding(); uint256 internal constant MAX_COMPACT_ENCODABLE_UINT = 2 ** 30 - 1; @@ -126,4 +130,20 @@ library ScaleCodec { } return encodeCompactU32(uint32(value)); } + + // Supports compact encoding of integers in [0, uint64.MAX] + function encodeCompactU64(uint64 value) internal pure returns (bytes memory) { + if (value <= 2 ** 30 - 1) { + return encodeCompactU32(uint32(value)); + } else { + uint8 countOfZeros = value.leadingZeros(); + uint8 bytesNeeded = 8 - countOfZeros / 8; + bytes memory result = abi.encodePacked(3 + ((bytesNeeded - 4) << 2)); + for (uint8 i = 0; i < bytesNeeded; i++) { + result = bytes.concat(result, abi.encodePacked(uint8(value))); + value >>= 8; + } + return result; + } + } } diff --git a/contracts/test/ScaleCodec.t.sol b/contracts/test/ScaleCodec.t.sol index 0e23b0982d..e6e135e9ea 100644 --- a/contracts/test/ScaleCodec.t.sol +++ b/contracts/test/ScaleCodec.t.sol @@ -47,4 +47,16 @@ contract ScaleCodecTest is Test { vm.expectRevert(ScaleCodec.UnsupportedCompactEncoding.selector); ScaleCodec.checkedEncodeCompactU32(uint256(type(uint32).max) + 1); } + + function testEncodeCompactU64() public { + assertEq(ScaleCodec.encodeCompactU64(0), hex"00"); + assertEq(ScaleCodec.encodeCompactU64(63), hex"fc"); + assertEq(ScaleCodec.encodeCompactU64(64), hex"0101"); + assertEq(ScaleCodec.encodeCompactU64(16383), hex"fdff"); + assertEq(ScaleCodec.encodeCompactU64(16384), hex"02000100"); + assertEq(ScaleCodec.encodeCompactU64(1073741823), hex"feffffff"); + assertEq(ScaleCodec.encodeCompactU64(1073741824), hex"0300000040"); + assertEq(ScaleCodec.encodeCompactU64(type(uint32).max), hex"03ffffffff"); + assertEq(ScaleCodec.encodeCompactU64(type(uint64).max), hex"13ffffffffffffffff"); + } } diff --git a/relayer/contracts/gateway.go b/relayer/contracts/gateway.go index e91becd0a0..048be4e7d3 100644 --- a/relayer/contracts/gateway.go +++ b/relayer/contracts/gateway.go @@ -47,14 +47,6 @@ type MultiAddress struct { Data []byte } -// TransactMessage is an auto generated low-level Go binding around an user-defined struct. -type TransactMessage struct { - OriginKind uint8 - Fee *big.Int - WeightAtMost Weight - Call []byte -} - // VerificationDigestItem is an auto generated low-level Go binding around an user-defined struct. type VerificationDigestItem struct { Kind *big.Int @@ -105,7 +97,7 @@ type Weight struct { // GatewayMetaData contains all meta data concerning the Gateway contract. var GatewayMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"function\",\"name\":\"agentOf\",\"inputs\":[{\"name\":\"agentID\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"channelNoncesOf\",\"inputs\":[{\"name\":\"channelID\",\"type\":\"bytes32\",\"internalType\":\"ChannelID\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"channelOperatingModeOf\",\"inputs\":[{\"name\":\"channelID\",\"type\":\"bytes32\",\"internalType\":\"ChannelID\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"enumOperatingMode\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"implementation\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isTokenRegistered\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"operatingMode\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"enumOperatingMode\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pricingParameters\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"UD60x18\"},{\"name\":\"\",\"type\":\"uint128\",\"internalType\":\"uint128\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"quoteRegisterTokenFee\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"quoteSendTokenFee\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"destinationChain\",\"type\":\"uint32\",\"internalType\":\"ParaID\"},{\"name\":\"destinationFee\",\"type\":\"uint128\",\"internalType\":\"uint128\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"registerToken\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"sendToken\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"destinationChain\",\"type\":\"uint32\",\"internalType\":\"ParaID\"},{\"name\":\"destinationAddress\",\"type\":\"tuple\",\"internalType\":\"structMultiAddress\",\"components\":[{\"name\":\"kind\",\"type\":\"uint8\",\"internalType\":\"enumKind\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"destinationFee\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"amount\",\"type\":\"uint128\",\"internalType\":\"uint128\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"submitV1\",\"inputs\":[{\"name\":\"message\",\"type\":\"tuple\",\"internalType\":\"structInboundMessage\",\"components\":[{\"name\":\"channelID\",\"type\":\"bytes32\",\"internalType\":\"ChannelID\"},{\"name\":\"nonce\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"command\",\"type\":\"uint8\",\"internalType\":\"enumCommand\"},{\"name\":\"params\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"maxDispatchGas\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"maxFeePerGas\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"reward\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"id\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"name\":\"leafProof\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"},{\"name\":\"headerProof\",\"type\":\"tuple\",\"internalType\":\"structVerification.Proof\",\"components\":[{\"name\":\"header\",\"type\":\"tuple\",\"internalType\":\"structVerification.ParachainHeader\",\"components\":[{\"name\":\"parentHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"number\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"stateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"extrinsicsRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"digestItems\",\"type\":\"tuple[]\",\"internalType\":\"structVerification.DigestItem[]\",\"components\":[{\"name\":\"kind\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"consensusEngineID\",\"type\":\"bytes4\",\"internalType\":\"bytes4\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}]},{\"name\":\"headProof\",\"type\":\"tuple\",\"internalType\":\"structVerification.HeadProof\",\"components\":[{\"name\":\"pos\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"width\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"proof\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"}]},{\"name\":\"leafPartial\",\"type\":\"tuple\",\"internalType\":\"structVerification.MMRLeafPartial\",\"components\":[{\"name\":\"version\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"parentNumber\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"parentHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"nextAuthoritySetID\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"nextAuthoritySetLen\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"nextAuthoritySetRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"name\":\"leafProof\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"},{\"name\":\"leafProofOrder\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"transact\",\"inputs\":[{\"name\":\"destinationChain\",\"type\":\"uint32\",\"internalType\":\"ParaID\"},{\"name\":\"message\",\"type\":\"tuple\",\"internalType\":\"structTransactMessage\",\"components\":[{\"name\":\"originKind\",\"type\":\"uint8\",\"internalType\":\"enumOriginKind\"},{\"name\":\"fee\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"weightAtMost\",\"type\":\"tuple\",\"internalType\":\"structWeight\",\"components\":[{\"name\":\"refTime\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"proofSize\",\"type\":\"uint64\",\"internalType\":\"uint64\"}]},{\"name\":\"call\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"event\",\"name\":\"AgentCreated\",\"inputs\":[{\"name\":\"agentID\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"},{\"name\":\"agent\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"AgentFundsWithdrawn\",\"inputs\":[{\"name\":\"agentID\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"recipient\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ChannelCreated\",\"inputs\":[{\"name\":\"channelID\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"ChannelID\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ChannelUpdated\",\"inputs\":[{\"name\":\"channelID\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"ChannelID\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"InboundMessageDispatched\",\"inputs\":[{\"name\":\"channelID\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"ChannelID\"},{\"name\":\"nonce\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"},{\"name\":\"messageID\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"success\",\"type\":\"bool\",\"indexed\":false,\"internalType\":\"bool\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatingModeChanged\",\"inputs\":[{\"name\":\"mode\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"enumOperatingMode\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OutboundMessageAccepted\",\"inputs\":[{\"name\":\"channelID\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"ChannelID\"},{\"name\":\"nonce\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"},{\"name\":\"messageID\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"payload\",\"type\":\"bytes\",\"indexed\":false,\"internalType\":\"bytes\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PricingParametersChanged\",\"inputs\":[],\"anonymous\":false},{\"type\":\"event\",\"name\":\"TokenRegistrationSent\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"TokenSent\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"sender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"destinationChain\",\"type\":\"uint32\",\"indexed\":true,\"internalType\":\"ParaID\"},{\"name\":\"destinationAddress\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structMultiAddress\",\"components\":[{\"name\":\"kind\",\"type\":\"uint8\",\"internalType\":\"enumKind\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"amount\",\"type\":\"uint128\",\"indexed\":false,\"internalType\":\"uint128\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"TokenTransferFeesChanged\",\"inputs\":[],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Upgraded\",\"inputs\":[{\"name\":\"implementation\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false}]", + ABI: "[{\"type\":\"function\",\"name\":\"agentOf\",\"inputs\":[{\"name\":\"agentID\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"channelNoncesOf\",\"inputs\":[{\"name\":\"channelID\",\"type\":\"bytes32\",\"internalType\":\"ChannelID\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"channelOperatingModeOf\",\"inputs\":[{\"name\":\"channelID\",\"type\":\"bytes32\",\"internalType\":\"ChannelID\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"enumOperatingMode\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"implementation\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isTokenRegistered\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"operatingMode\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"enumOperatingMode\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pricingParameters\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"UD60x18\"},{\"name\":\"\",\"type\":\"uint128\",\"internalType\":\"uint128\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"quoteRegisterTokenFee\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"quoteSendCallFee\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"quoteSendTokenFee\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"destinationChain\",\"type\":\"uint32\",\"internalType\":\"ParaID\"},{\"name\":\"destinationFee\",\"type\":\"uint128\",\"internalType\":\"uint128\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"registerToken\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"sendCall\",\"inputs\":[{\"name\":\"destinationChain\",\"type\":\"uint32\",\"internalType\":\"ParaID\"},{\"name\":\"originKind\",\"type\":\"uint8\",\"internalType\":\"enumOriginKind\"},{\"name\":\"destinationFee\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"weightAtMost\",\"type\":\"tuple\",\"internalType\":\"structWeight\",\"components\":[{\"name\":\"refTime\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"proofSize\",\"type\":\"uint64\",\"internalType\":\"uint64\"}]},{\"name\":\"call\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"sendToken\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"destinationChain\",\"type\":\"uint32\",\"internalType\":\"ParaID\"},{\"name\":\"destinationAddress\",\"type\":\"tuple\",\"internalType\":\"structMultiAddress\",\"components\":[{\"name\":\"kind\",\"type\":\"uint8\",\"internalType\":\"enumKind\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"destinationFee\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"amount\",\"type\":\"uint128\",\"internalType\":\"uint128\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"submitV1\",\"inputs\":[{\"name\":\"message\",\"type\":\"tuple\",\"internalType\":\"structInboundMessage\",\"components\":[{\"name\":\"channelID\",\"type\":\"bytes32\",\"internalType\":\"ChannelID\"},{\"name\":\"nonce\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"command\",\"type\":\"uint8\",\"internalType\":\"enumCommand\"},{\"name\":\"params\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"maxDispatchGas\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"maxFeePerGas\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"reward\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"id\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"name\":\"leafProof\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"},{\"name\":\"headerProof\",\"type\":\"tuple\",\"internalType\":\"structVerification.Proof\",\"components\":[{\"name\":\"header\",\"type\":\"tuple\",\"internalType\":\"structVerification.ParachainHeader\",\"components\":[{\"name\":\"parentHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"number\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"stateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"extrinsicsRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"digestItems\",\"type\":\"tuple[]\",\"internalType\":\"structVerification.DigestItem[]\",\"components\":[{\"name\":\"kind\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"consensusEngineID\",\"type\":\"bytes4\",\"internalType\":\"bytes4\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}]},{\"name\":\"headProof\",\"type\":\"tuple\",\"internalType\":\"structVerification.HeadProof\",\"components\":[{\"name\":\"pos\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"width\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"proof\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"}]},{\"name\":\"leafPartial\",\"type\":\"tuple\",\"internalType\":\"structVerification.MMRLeafPartial\",\"components\":[{\"name\":\"version\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"parentNumber\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"parentHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"nextAuthoritySetID\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"nextAuthoritySetLen\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"nextAuthoritySetRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"name\":\"leafProof\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"},{\"name\":\"leafProofOrder\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"AgentCreated\",\"inputs\":[{\"name\":\"agentID\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"},{\"name\":\"agent\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"AgentFundsWithdrawn\",\"inputs\":[{\"name\":\"agentID\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"recipient\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ChannelCreated\",\"inputs\":[{\"name\":\"channelID\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"ChannelID\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ChannelUpdated\",\"inputs\":[{\"name\":\"channelID\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"ChannelID\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"InboundMessageDispatched\",\"inputs\":[{\"name\":\"channelID\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"ChannelID\"},{\"name\":\"nonce\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"},{\"name\":\"messageID\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"success\",\"type\":\"bool\",\"indexed\":false,\"internalType\":\"bool\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatingModeChanged\",\"inputs\":[{\"name\":\"mode\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"enumOperatingMode\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OutboundMessageAccepted\",\"inputs\":[{\"name\":\"channelID\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"ChannelID\"},{\"name\":\"nonce\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"},{\"name\":\"messageID\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"payload\",\"type\":\"bytes\",\"indexed\":false,\"internalType\":\"bytes\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PricingParametersChanged\",\"inputs\":[],\"anonymous\":false},{\"type\":\"event\",\"name\":\"TokenRegistrationSent\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"TokenSent\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"sender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"destinationChain\",\"type\":\"uint32\",\"indexed\":true,\"internalType\":\"ParaID\"},{\"name\":\"destinationAddress\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structMultiAddress\",\"components\":[{\"name\":\"kind\",\"type\":\"uint8\",\"internalType\":\"enumKind\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"amount\",\"type\":\"uint128\",\"indexed\":false,\"internalType\":\"uint128\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"TokenTransferFeesChanged\",\"inputs\":[],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Upgraded\",\"inputs\":[{\"name\":\"implementation\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false}]", } // GatewayABI is the input ABI used to generate the binding from. @@ -504,6 +496,37 @@ func (_Gateway *GatewayCallerSession) QuoteRegisterTokenFee() (*big.Int, error) return _Gateway.Contract.QuoteRegisterTokenFee(&_Gateway.CallOpts) } +// QuoteSendCallFee is a free data retrieval call binding the contract method 0x1690cd14. +// +// Solidity: function quoteSendCallFee() view returns(uint256) +func (_Gateway *GatewayCaller) QuoteSendCallFee(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Gateway.contract.Call(opts, &out, "quoteSendCallFee") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// QuoteSendCallFee is a free data retrieval call binding the contract method 0x1690cd14. +// +// Solidity: function quoteSendCallFee() view returns(uint256) +func (_Gateway *GatewaySession) QuoteSendCallFee() (*big.Int, error) { + return _Gateway.Contract.QuoteSendCallFee(&_Gateway.CallOpts) +} + +// QuoteSendCallFee is a free data retrieval call binding the contract method 0x1690cd14. +// +// Solidity: function quoteSendCallFee() view returns(uint256) +func (_Gateway *GatewayCallerSession) QuoteSendCallFee() (*big.Int, error) { + return _Gateway.Contract.QuoteSendCallFee(&_Gateway.CallOpts) +} + // QuoteSendTokenFee is a free data retrieval call binding the contract method 0x928bc49d. // // Solidity: function quoteSendTokenFee(address token, uint32 destinationChain, uint128 destinationFee) view returns(uint256) @@ -556,6 +579,27 @@ func (_Gateway *GatewayTransactorSession) RegisterToken(token common.Address) (* return _Gateway.Contract.RegisterToken(&_Gateway.TransactOpts, token) } +// SendCall is a paid mutator transaction binding the contract method 0x86c2b257. +// +// Solidity: function sendCall(uint32 destinationChain, uint8 originKind, uint128 destinationFee, (uint64,uint64) weightAtMost, bytes call) payable returns() +func (_Gateway *GatewayTransactor) SendCall(opts *bind.TransactOpts, destinationChain uint32, originKind uint8, destinationFee *big.Int, weightAtMost Weight, call []byte) (*types.Transaction, error) { + return _Gateway.contract.Transact(opts, "sendCall", destinationChain, originKind, destinationFee, weightAtMost, call) +} + +// SendCall is a paid mutator transaction binding the contract method 0x86c2b257. +// +// Solidity: function sendCall(uint32 destinationChain, uint8 originKind, uint128 destinationFee, (uint64,uint64) weightAtMost, bytes call) payable returns() +func (_Gateway *GatewaySession) SendCall(destinationChain uint32, originKind uint8, destinationFee *big.Int, weightAtMost Weight, call []byte) (*types.Transaction, error) { + return _Gateway.Contract.SendCall(&_Gateway.TransactOpts, destinationChain, originKind, destinationFee, weightAtMost, call) +} + +// SendCall is a paid mutator transaction binding the contract method 0x86c2b257. +// +// Solidity: function sendCall(uint32 destinationChain, uint8 originKind, uint128 destinationFee, (uint64,uint64) weightAtMost, bytes call) payable returns() +func (_Gateway *GatewayTransactorSession) SendCall(destinationChain uint32, originKind uint8, destinationFee *big.Int, weightAtMost Weight, call []byte) (*types.Transaction, error) { + return _Gateway.Contract.SendCall(&_Gateway.TransactOpts, destinationChain, originKind, destinationFee, weightAtMost, call) +} + // SendToken is a paid mutator transaction binding the contract method 0x52054834. // // Solidity: function sendToken(address token, uint32 destinationChain, (uint8,bytes) destinationAddress, uint128 destinationFee, uint128 amount) payable returns() @@ -598,27 +642,6 @@ func (_Gateway *GatewayTransactorSession) SubmitV1(message InboundMessage, leafP return _Gateway.Contract.SubmitV1(&_Gateway.TransactOpts, message, leafProof, headerProof) } -// Transact is a paid mutator transaction binding the contract method 0xbb450536. -// -// Solidity: function transact(uint32 destinationChain, (uint8,uint128,(uint64,uint64),bytes) message) payable returns() -func (_Gateway *GatewayTransactor) Transact(opts *bind.TransactOpts, destinationChain uint32, message TransactMessage) (*types.Transaction, error) { - return _Gateway.contract.Transact(opts, "transact", destinationChain, message) -} - -// Transact is a paid mutator transaction binding the contract method 0xbb450536. -// -// Solidity: function transact(uint32 destinationChain, (uint8,uint128,(uint64,uint64),bytes) message) payable returns() -func (_Gateway *GatewaySession) Transact(destinationChain uint32, message TransactMessage) (*types.Transaction, error) { - return _Gateway.Contract.Transact(&_Gateway.TransactOpts, destinationChain, message) -} - -// Transact is a paid mutator transaction binding the contract method 0xbb450536. -// -// Solidity: function transact(uint32 destinationChain, (uint8,uint128,(uint64,uint64),bytes) message) payable returns() -func (_Gateway *GatewayTransactorSession) Transact(destinationChain uint32, message TransactMessage) (*types.Transaction, error) { - return _Gateway.Contract.Transact(&_Gateway.TransactOpts, destinationChain, message) -} - // GatewayAgentCreatedIterator is returned from FilterAgentCreated and is used to iterate over the raw logs and unpacked data for AgentCreated events raised by the Gateway contract. type GatewayAgentCreatedIterator struct { Event *GatewayAgentCreated // Event containing the contract specifics and raw log diff --git a/smoketest/tests/transact_from_eth_to_penpal.rs b/smoketest/tests/transact_from_eth_to_penpal.rs index 3d46176abd..8b86236da3 100644 --- a/smoketest/tests/transact_from_eth_to_penpal.rs +++ b/smoketest/tests/transact_from_eth_to_penpal.rs @@ -3,7 +3,7 @@ use futures::StreamExt; use hex_literal::hex; use snowbridge_smoketest::{ constants::*, - contracts::{gateway_upgrade_mock::TransactMessage, i_gateway, shared_types::Weight}, + contracts::{i_gateway, shared_types::Weight}, helper::{initial_clients, print_event_log_for_unit_tests}, parachains::penpal::api::system::events::Remarked, }; @@ -17,16 +17,14 @@ async fn transact_from_eth_to_penpal() { let gateway_addr: Address = GATEWAY_PROXY_CONTRACT.into(); let gateway = i_gateway::IGateway::new(gateway_addr, ethereum_client.clone()); - let message = TransactMessage { - origin_kind: 0, - fee: 40_000_000_000, - weight_at_most: Weight { ref_time: 40_000_000, proof_size: 8_000 }, - //system.remark - call: Bytes::from(hex!("00071468656c6c6f").to_vec()), - }; - let receipt = gateway - .transact(PENPAL_PARA_ID, message) + .send_call( + PENPAL_PARA_ID, + 0, + 40_000_000_000, + Weight { ref_time: 40_000_000, proof_size: 8_000 }, + Bytes::from(hex!("00071468656c6c6f").to_vec()), + ) .value::(100_000_000_000_000_000_u128.into()) .send() .await From 2f3560ce09e2dbbd45c5f49307f52731f61efada Mon Sep 17 00:00:00 2001 From: ron Date: Fri, 23 Feb 2024 16:57:09 +0800 Subject: [PATCH 22/37] Fix smoke test with sovereign account of the sender --- web/packages/test/scripts/configure-penpal.sh | 9 +++++---- web/packages/test/scripts/set-env.sh | 4 ++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/web/packages/test/scripts/configure-penpal.sh b/web/packages/test/scripts/configure-penpal.sh index 4ebed29e2e..95526accb1 100755 --- a/web/packages/test/scripts/configure-penpal.sh +++ b/web/packages/test/scripts/configure-penpal.sh @@ -4,13 +4,14 @@ set -eu source scripts/set-env.sh source scripts/xcm-helper.sh -fund_bridgehub_sovereign() { - local call="0x0a08007369626cf5030000000000000000000000000000000000000000000000000000070010a5d4e8" - send_governance_transact_from_relaychain $PENPAL_PARAID "$call" +fund_sender_sovereign() { + # forceSetBalance($sender_sovereign_account, 1000000000000) + local transact_call="0x0a0800"$sender_sovereign_account"070010a5d4e8" + send_governance_transact_from_relaychain $PENPAL_PARAID "$transact_call" } configure_penpal() { - fund_bridgehub_sovereign + fund_sender_sovereign } if [ -z "${from_start_services:-}" ]; then diff --git a/web/packages/test/scripts/set-env.sh b/web/packages/test/scripts/set-env.sh index 5fbaf0be19..0447676ee9 100755 --- a/web/packages/test/scripts/set-env.sh +++ b/web/packages/test/scripts/set-env.sh @@ -72,12 +72,12 @@ penpal_sovereign_account="${PENPAL_SOVEREIGN_ACCOUNT:-0x7369626cd007000000000000 beacon_relayer_pub_key="${BEACON_RELAYER_PUB_KEY:-0xc46e141b5083721ad5f5056ba1cded69dce4a65f027ed3362357605b1687986a}" # Execution relay account (//ExecutionRelay 5CFNWKMFPsw5Cs2Teo6Pvg7rWyjKiFfqPZs8U4MZXzMYFwXL in testnet) execution_relayer_pub_key="${EXECUTION_RELAYER_PUB_KEY:-0x08228efd065c58a043da95c8bf177659fc587643e71e7ed1534666177730196f}" +# Sovereign account for msg.sender in penpal (Ethereum address:0x90A987B944Cb1dCcE5564e5FDeCD7a54D3de27Fe) +sender_sovereign_account="ee99e7e8ac49f08251154c033f827541f4fb8a5b1fc4d6d9b1ab72c103bd3023" # Config for deploying contracts - ## Deployment key export PRIVATE_KEY="${DEPLOYER_ETH_KEY:-0x4e9444a6efd6d42725a250b650a781da2737ea308c839eaccb0f7f3dbd2fea77}" - ## BeefyClient # For max safety delay should be MAX_SEED_LOOKAHEAD=4 epochs=4*8*6=192s # but for rococo-local each session is only 20 slots=120s From e99ce53791c596ec19d89b1e0d0e804c3d012fce Mon Sep 17 00:00:00 2001 From: ron Date: Mon, 26 Feb 2024 13:42:29 +0800 Subject: [PATCH 23/37] Fix generate inbound fixture --- relayer/cmd/generate_beacon_data.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/relayer/cmd/generate_beacon_data.go b/relayer/cmd/generate_beacon_data.go index a6eecb998c..7af697870d 100644 --- a/relayer/cmd/generate_beacon_data.go +++ b/relayer/cmd/generate_beacon_data.go @@ -41,6 +41,7 @@ func generateBeaconDataCmd() *cobra.Command { cmd.Flags().Bool("wait_until_next_period", true, "Waiting until next period") cmd.Flags().Uint32("nonce", 1, "Nonce of the inbound message") cmd.Flags().String("test_case", "register_token", "Inbound test case") + cmd.Flags().String("execution_relay_config", "/tmp/snowbridge/execution-relay-asset-hub.json", "Config file for execution relayer") return cmd } @@ -161,7 +162,12 @@ func generateBeaconTestFixture(cmd *cobra.Command, _ []string) error { log.WithFields(log.Fields{"endpoint": endpoint}).Info("connecting to beacon API") s := syncer.New(endpoint, conf.Source.Beacon.Spec) - viper.SetConfigFile("/tmp/snowbridge/execution-relay-asset-hub.json") + executionRelayConfig, err := cmd.Flags().GetString("execution_relay_config") + if err != nil { + return err + } + + viper.SetConfigFile(executionRelayConfig) if err = viper.ReadInConfig(); err != nil { return err @@ -380,7 +386,7 @@ func generateBeaconTestFixture(cmd *cobra.Command, _ []string) error { if err != nil { return err } - if testCase != "register_token" && testCase != "send_token" { + if testCase != "register_token" && testCase != "send_token" && testCase != "send_call_to_penpal" && testCase != "send_call_to_penpal" { return fmt.Errorf("invalid test case: %s", testCase) } pathToInboundQueueFixtureTemplate := fmt.Sprintf(pathToInboundQueueFixtureTemplate, testCase) From 3d91da451aeae9a88475ec881cdd6a44846982d5 Mon Sep 17 00:00:00 2001 From: ron Date: Wed, 6 Mar 2024 22:09:44 +0800 Subject: [PATCH 24/37] Support TransactFeeMode --- contracts/src/Gateway.sol | 32 ++++++++++++++++----- contracts/src/SubstrateTypes.sol | 14 +++++---- contracts/src/Types.sol | 19 ++++++++++++ contracts/src/interfaces/IGateway.sol | 14 +++++++-- contracts/test/Gateway.t.sol | 26 +++++++++++------ contracts/test/mocks/GatewayUpgradeMock.sol | 6 ++-- 6 files changed, 87 insertions(+), 24 deletions(-) diff --git a/contracts/src/Gateway.sol b/contracts/src/Gateway.sol index 13614bfb9b..be6285e7e3 100644 --- a/contracts/src/Gateway.sol +++ b/contracts/src/Gateway.sol @@ -19,7 +19,8 @@ import { Ticket, Costs, OriginKind, - Weight + Weight, + TransactFeeMode } from "./Types.sol"; import {IGateway} from "./interfaces/IGateway.sol"; import {IInitializable} from "./interfaces/IInitializable.sol"; @@ -627,23 +628,40 @@ contract Gateway is IGateway, IInitializable { assets.assetHubReserveTransferFee = config.assetHubReserveTransferFee; } + // Calculate cost for transact + function _calculateTransactCost(TransactFeeMode feeMode, uint128 destinationFee) + internal + pure + returns (Costs memory costs) + { + if (feeMode == TransactFeeMode.OnEthereum) { + costs = Costs({native: 0, foreign: destinationFee}); + } else if (feeMode == TransactFeeMode.OnSubstrate) { + costs = Costs({native: 0, foreign: 0}); + } + return costs; + } + /// @inheritdoc IGateway function sendCall( ParaID destinationChain, OriginKind originKind, + TransactFeeMode feeMode, uint128 destinationFee, Weight calldata weightAtMost, bytes calldata call ) external payable { - bytes memory payload = - SubstrateTypes.Transact(msg.sender, originKind.encode(), destinationFee, weightAtMost, call); - Ticket memory ticket = Ticket({dest: destinationChain, costs: Costs({native: 0, foreign: 0}), payload: payload}); + bytes memory payload = SubstrateTypes.Transact( + msg.sender, originKind.encode(), feeMode.encodeFeeMode(), destinationFee, weightAtMost, call + ); + Costs memory costs = _calculateTransactCost(feeMode, destinationFee); + Ticket memory ticket = Ticket({dest: destinationChain, costs: costs, payload: payload}); _submitOutbound(ticket); } /// @inheritdoc IGateway - function quoteSendCallFee() external view returns (uint256) { - PricingStorage.Layout storage pricing = PricingStorage.layout(); - return _convertToNative(pricing.exchangeRate, pricing.deliveryCost); + function quoteSendCallFee(TransactFeeMode feeMode, uint128 destinationFee) external view returns (uint256) { + Costs memory costs = _calculateTransactCost(feeMode, destinationFee); + return _calculateFee(costs); } } diff --git a/contracts/src/SubstrateTypes.sol b/contracts/src/SubstrateTypes.sol index 43d1b835f8..3319570f20 100644 --- a/contracts/src/SubstrateTypes.sol +++ b/contracts/src/SubstrateTypes.sol @@ -135,17 +135,21 @@ library SubstrateTypes { } // Arbitrary transact - function Transact(address sender, bytes1 originKind, uint128 fee, Weight memory weight, bytes memory call) - internal - view - returns (bytes memory) - { + function Transact( + address sender, + bytes1 originKind, + bytes1 feeMode, + uint128 fee, + Weight memory weight, + bytes memory call + ) internal view returns (bytes memory) { return bytes.concat( bytes1(0x00), ScaleCodec.encodeU64(uint64(block.chainid)), bytes1(0x02), SubstrateTypes.H160(sender), originKind, + feeMode, ScaleCodec.encodeU128(fee), ScaleCodec.encodeCompactU64(weight.refTime), ScaleCodec.encodeCompactU64(weight.proofSize), diff --git a/contracts/src/Types.sol b/contracts/src/Types.sol index 6c782e3c6e..ea366bcb41 100644 --- a/contracts/src/Types.sol +++ b/contracts/src/Types.sol @@ -131,3 +131,22 @@ function encode(OriginKind kind) pure returns (bytes1 result) { } return result; } + +/// @dev FeeMode +enum TransactFeeMode { + /// @dev Transact Fee paid full on Ethereum side upfront + OnEthereum, + /// @dev Transact Fee paid on destination chain by prefunded sender + OnSubstrate +} + +using {encodeFeeMode} for TransactFeeMode global; + +function encodeFeeMode(TransactFeeMode kind) pure returns (bytes1 result) { + if (kind == TransactFeeMode.OnEthereum) { + result = 0x00; + } else if (kind == TransactFeeMode.OnSubstrate) { + result = 0x01; + } + return result; +} diff --git a/contracts/src/interfaces/IGateway.sol b/contracts/src/interfaces/IGateway.sol index de11a39956..890b6613aa 100644 --- a/contracts/src/interfaces/IGateway.sol +++ b/contracts/src/interfaces/IGateway.sol @@ -2,7 +2,16 @@ // SPDX-FileCopyrightText: 2023 Snowfork pragma solidity 0.8.23; -import {OperatingMode, InboundMessage, ParaID, ChannelID, MultiAddress, OriginKind, Weight} from "../Types.sol"; +import { + OperatingMode, + InboundMessage, + ParaID, + ChannelID, + MultiAddress, + OriginKind, + Weight, + TransactFeeMode +} from "../Types.sol"; import {Verification} from "../Verification.sol"; import {UD60x18} from "prb/math/src/UD60x18.sol"; @@ -110,11 +119,12 @@ interface IGateway { function sendCall( ParaID destinationChain, OriginKind originKind, + TransactFeeMode feeMode, uint128 destinationFee, Weight calldata weightAtMost, bytes calldata call ) external payable; /// @dev Quote a fee in Ether for transact - function quoteSendCallFee() external view returns (uint256); + function quoteSendCallFee(TransactFeeMode feeMode, uint128 destinationFee) external view returns (uint256); } diff --git a/contracts/test/Gateway.t.sol b/contracts/test/Gateway.t.sol index afb5884b31..a948cbec8f 100644 --- a/contracts/test/Gateway.t.sol +++ b/contracts/test/Gateway.t.sol @@ -44,7 +44,8 @@ import { multiAddressFromBytes32, multiAddressFromBytes20, Weight, - OriginKind + OriginKind, + TransactFeeMode } from "../src/Types.sol"; import {WETH9} from "canonical-weth/WETH9.sol"; @@ -919,35 +920,44 @@ contract GatewayTest is Test { * Transact */ function testTransactFromXcmOrigin() public { - bytes memory payload = SubstrateTypes.Transact(account1, 0x03, 1, Weight(1, 1), bytes("0x1")); + bytes memory payload = SubstrateTypes.Transact(account1, 0x03, 0x01, 1, Weight(1, 1), bytes("0x1")); console.logBytes(payload); vm.expectEmit(true, false, false, true); emit IGateway.OutboundMessageAccepted(penpalParaID.into(), 1, messageID, payload); hoax(address(account1)); - IGateway(address(gateway)).sendCall{value: 1 ether}(penpalParaID, OriginKind.Xcm, 1, Weight(1, 1), bytes("0x1")); + IGateway(address(gateway)).sendCall{value: 1 ether}( + penpalParaID, OriginKind.Xcm, TransactFeeMode.OnSubstrate, 1, Weight(1, 1), bytes("0x1") + ); } function testTransactFromSovereignAccount() public { - bytes memory payload = SubstrateTypes.Transact(account1, 0x01, 1, Weight(1, 1), bytes("0x1")); + bytes memory payload = SubstrateTypes.Transact(account1, 0x01, 0x00, 1, Weight(1, 1), bytes("0x1")); console.logBytes(payload); vm.expectEmit(true, false, false, true); emit IGateway.OutboundMessageAccepted(penpalParaID.into(), 1, messageID, payload); hoax(address(account1)); IGateway(address(gateway)).sendCall{value: 1 ether}( - penpalParaID, OriginKind.SovereignAccount, 1, Weight(1, 1), bytes("0x1") + penpalParaID, OriginKind.SovereignAccount, TransactFeeMode.OnEthereum, 1, Weight(1, 1), bytes("0x1") ); } function testTransactFromSovereignAccountWithFee() public { - bytes memory payload = SubstrateTypes.Transact(account1, 0x01, 1, Weight(1, 1), bytes("0x1")); + bytes memory payload = SubstrateTypes.Transact(account1, 0x01, 0x01, 1, Weight(1, 1), bytes("0x1")); console.logBytes(payload); - uint256 fee = IGateway(address(gateway)).quoteSendCallFee(); + uint256 fee = IGateway(address(gateway)).quoteSendCallFee(TransactFeeMode.OnSubstrate, 1); assertEq(fee, 2500000000000000); vm.expectEmit(true, false, false, true); emit IGateway.OutboundMessageAccepted(penpalParaID.into(), 1, messageID, payload); hoax(address(account1)); IGateway(address(gateway)).sendCall{value: fee}( - penpalParaID, OriginKind.SovereignAccount, 1, Weight(1, 1), bytes("0x1") + penpalParaID, OriginKind.SovereignAccount, TransactFeeMode.OnSubstrate, 1, Weight(1, 1), bytes("0x1") ); } + + function testQuoteSendCallFee() public { + uint256 fee = IGateway(address(gateway)).quoteSendCallFee(TransactFeeMode.OnSubstrate, 1); + assertEq(fee, 2500000000000000); + fee = IGateway(address(gateway)).quoteSendCallFee(TransactFeeMode.OnEthereum, 1); + assertEq(fee, 2500000000250000); + } } diff --git a/contracts/test/mocks/GatewayUpgradeMock.sol b/contracts/test/mocks/GatewayUpgradeMock.sol index ddf6d545c5..ac660a5a96 100644 --- a/contracts/test/mocks/GatewayUpgradeMock.sol +++ b/contracts/test/mocks/GatewayUpgradeMock.sol @@ -11,7 +11,8 @@ import { ChannelID, MultiAddress, OriginKind, - Weight + Weight, + TransactFeeMode } from "../../src/Types.sol"; import {IGateway} from "../../src/interfaces/IGateway.sol"; import {IInitializable} from "../../src/interfaces/IInitializable.sol"; @@ -75,12 +76,13 @@ contract GatewayUpgradeMock is IGateway, IInitializable { function sendCall( ParaID destinationChain, OriginKind originKind, + TransactFeeMode feeMode, uint128 destinationFee, Weight calldata weightAtMost, bytes calldata call ) external payable {} - function quoteSendCallFee() external pure returns (uint256) { + function quoteSendCallFee(TransactFeeMode, uint128) external pure returns (uint256) { return 1; } } From 68a567f60f688dd532524ea61c961ff7e89d371b Mon Sep 17 00:00:00 2001 From: ron Date: Tue, 19 Mar 2024 17:15:47 +0800 Subject: [PATCH 25/37] Remove prefunding mode --- contracts/src/Gateway.sol | 28 ++++++--------------- contracts/src/SubstrateTypes.sol | 14 ++++------- contracts/src/Types.sol | 19 -------------- contracts/src/interfaces/IGateway.sol | 14 ++--------- contracts/test/Gateway.t.sol | 25 ++++++++---------- contracts/test/mocks/GatewayUpgradeMock.sol | 6 ++--- 6 files changed, 27 insertions(+), 79 deletions(-) diff --git a/contracts/src/Gateway.sol b/contracts/src/Gateway.sol index be6285e7e3..3697210d08 100644 --- a/contracts/src/Gateway.sol +++ b/contracts/src/Gateway.sol @@ -19,8 +19,7 @@ import { Ticket, Costs, OriginKind, - Weight, - TransactFeeMode + Weight } from "./Types.sol"; import {IGateway} from "./interfaces/IGateway.sol"; import {IInitializable} from "./interfaces/IInitializable.sol"; @@ -629,39 +628,28 @@ contract Gateway is IGateway, IInitializable { } // Calculate cost for transact - function _calculateTransactCost(TransactFeeMode feeMode, uint128 destinationFee) - internal - pure - returns (Costs memory costs) - { - if (feeMode == TransactFeeMode.OnEthereum) { - costs = Costs({native: 0, foreign: destinationFee}); - } else if (feeMode == TransactFeeMode.OnSubstrate) { - costs = Costs({native: 0, foreign: 0}); - } - return costs; + function _calculateTransactCost(uint128 destinationFee) internal pure returns (Costs memory costs) { + return Costs({native: 0, foreign: destinationFee}); } /// @inheritdoc IGateway function sendCall( ParaID destinationChain, OriginKind originKind, - TransactFeeMode feeMode, uint128 destinationFee, Weight calldata weightAtMost, bytes calldata call ) external payable { - bytes memory payload = SubstrateTypes.Transact( - msg.sender, originKind.encode(), feeMode.encodeFeeMode(), destinationFee, weightAtMost, call - ); - Costs memory costs = _calculateTransactCost(feeMode, destinationFee); + bytes memory payload = + SubstrateTypes.Transact(msg.sender, originKind.encode(), destinationFee, weightAtMost, call); + Costs memory costs = _calculateTransactCost(destinationFee); Ticket memory ticket = Ticket({dest: destinationChain, costs: costs, payload: payload}); _submitOutbound(ticket); } /// @inheritdoc IGateway - function quoteSendCallFee(TransactFeeMode feeMode, uint128 destinationFee) external view returns (uint256) { - Costs memory costs = _calculateTransactCost(feeMode, destinationFee); + function quoteSendCallFee(uint128 destinationFee) external view returns (uint256) { + Costs memory costs = _calculateTransactCost(destinationFee); return _calculateFee(costs); } } diff --git a/contracts/src/SubstrateTypes.sol b/contracts/src/SubstrateTypes.sol index 3319570f20..43d1b835f8 100644 --- a/contracts/src/SubstrateTypes.sol +++ b/contracts/src/SubstrateTypes.sol @@ -135,21 +135,17 @@ library SubstrateTypes { } // Arbitrary transact - function Transact( - address sender, - bytes1 originKind, - bytes1 feeMode, - uint128 fee, - Weight memory weight, - bytes memory call - ) internal view returns (bytes memory) { + function Transact(address sender, bytes1 originKind, uint128 fee, Weight memory weight, bytes memory call) + internal + view + returns (bytes memory) + { return bytes.concat( bytes1(0x00), ScaleCodec.encodeU64(uint64(block.chainid)), bytes1(0x02), SubstrateTypes.H160(sender), originKind, - feeMode, ScaleCodec.encodeU128(fee), ScaleCodec.encodeCompactU64(weight.refTime), ScaleCodec.encodeCompactU64(weight.proofSize), diff --git a/contracts/src/Types.sol b/contracts/src/Types.sol index ea366bcb41..6c782e3c6e 100644 --- a/contracts/src/Types.sol +++ b/contracts/src/Types.sol @@ -131,22 +131,3 @@ function encode(OriginKind kind) pure returns (bytes1 result) { } return result; } - -/// @dev FeeMode -enum TransactFeeMode { - /// @dev Transact Fee paid full on Ethereum side upfront - OnEthereum, - /// @dev Transact Fee paid on destination chain by prefunded sender - OnSubstrate -} - -using {encodeFeeMode} for TransactFeeMode global; - -function encodeFeeMode(TransactFeeMode kind) pure returns (bytes1 result) { - if (kind == TransactFeeMode.OnEthereum) { - result = 0x00; - } else if (kind == TransactFeeMode.OnSubstrate) { - result = 0x01; - } - return result; -} diff --git a/contracts/src/interfaces/IGateway.sol b/contracts/src/interfaces/IGateway.sol index 890b6613aa..14dca9ac03 100644 --- a/contracts/src/interfaces/IGateway.sol +++ b/contracts/src/interfaces/IGateway.sol @@ -2,16 +2,7 @@ // SPDX-FileCopyrightText: 2023 Snowfork pragma solidity 0.8.23; -import { - OperatingMode, - InboundMessage, - ParaID, - ChannelID, - MultiAddress, - OriginKind, - Weight, - TransactFeeMode -} from "../Types.sol"; +import {OperatingMode, InboundMessage, ParaID, ChannelID, MultiAddress, OriginKind, Weight} from "../Types.sol"; import {Verification} from "../Verification.sol"; import {UD60x18} from "prb/math/src/UD60x18.sol"; @@ -119,12 +110,11 @@ interface IGateway { function sendCall( ParaID destinationChain, OriginKind originKind, - TransactFeeMode feeMode, uint128 destinationFee, Weight calldata weightAtMost, bytes calldata call ) external payable; /// @dev Quote a fee in Ether for transact - function quoteSendCallFee(TransactFeeMode feeMode, uint128 destinationFee) external view returns (uint256); + function quoteSendCallFee(uint128 destinationFee) external view returns (uint256); } diff --git a/contracts/test/Gateway.t.sol b/contracts/test/Gateway.t.sol index a948cbec8f..73cd40031d 100644 --- a/contracts/test/Gateway.t.sol +++ b/contracts/test/Gateway.t.sol @@ -44,8 +44,7 @@ import { multiAddressFromBytes32, multiAddressFromBytes20, Weight, - OriginKind, - TransactFeeMode + OriginKind } from "../src/Types.sol"; import {WETH9} from "canonical-weth/WETH9.sol"; @@ -920,44 +919,40 @@ contract GatewayTest is Test { * Transact */ function testTransactFromXcmOrigin() public { - bytes memory payload = SubstrateTypes.Transact(account1, 0x03, 0x01, 1, Weight(1, 1), bytes("0x1")); + bytes memory payload = SubstrateTypes.Transact(account1, 0x03, 1, Weight(1, 1), bytes("0x1")); console.logBytes(payload); vm.expectEmit(true, false, false, true); emit IGateway.OutboundMessageAccepted(penpalParaID.into(), 1, messageID, payload); hoax(address(account1)); - IGateway(address(gateway)).sendCall{value: 1 ether}( - penpalParaID, OriginKind.Xcm, TransactFeeMode.OnSubstrate, 1, Weight(1, 1), bytes("0x1") - ); + IGateway(address(gateway)).sendCall{value: 1 ether}(penpalParaID, OriginKind.Xcm, 1, Weight(1, 1), bytes("0x1")); } function testTransactFromSovereignAccount() public { - bytes memory payload = SubstrateTypes.Transact(account1, 0x01, 0x00, 1, Weight(1, 1), bytes("0x1")); + bytes memory payload = SubstrateTypes.Transact(account1, 0x01, 1, Weight(1, 1), bytes("0x1")); console.logBytes(payload); vm.expectEmit(true, false, false, true); emit IGateway.OutboundMessageAccepted(penpalParaID.into(), 1, messageID, payload); hoax(address(account1)); IGateway(address(gateway)).sendCall{value: 1 ether}( - penpalParaID, OriginKind.SovereignAccount, TransactFeeMode.OnEthereum, 1, Weight(1, 1), bytes("0x1") + penpalParaID, OriginKind.SovereignAccount, 1, Weight(1, 1), bytes("0x1") ); } function testTransactFromSovereignAccountWithFee() public { - bytes memory payload = SubstrateTypes.Transact(account1, 0x01, 0x01, 1, Weight(1, 1), bytes("0x1")); + bytes memory payload = SubstrateTypes.Transact(account1, 0x01, 1, Weight(1, 1), bytes("0x1")); console.logBytes(payload); - uint256 fee = IGateway(address(gateway)).quoteSendCallFee(TransactFeeMode.OnSubstrate, 1); - assertEq(fee, 2500000000000000); + uint256 fee = IGateway(address(gateway)).quoteSendCallFee(1); + assertEq(fee, 2500000000250000); vm.expectEmit(true, false, false, true); emit IGateway.OutboundMessageAccepted(penpalParaID.into(), 1, messageID, payload); hoax(address(account1)); IGateway(address(gateway)).sendCall{value: fee}( - penpalParaID, OriginKind.SovereignAccount, TransactFeeMode.OnSubstrate, 1, Weight(1, 1), bytes("0x1") + penpalParaID, OriginKind.SovereignAccount, 1, Weight(1, 1), bytes("0x1") ); } function testQuoteSendCallFee() public { - uint256 fee = IGateway(address(gateway)).quoteSendCallFee(TransactFeeMode.OnSubstrate, 1); - assertEq(fee, 2500000000000000); - fee = IGateway(address(gateway)).quoteSendCallFee(TransactFeeMode.OnEthereum, 1); + uint256 fee = IGateway(address(gateway)).quoteSendCallFee(1); assertEq(fee, 2500000000250000); } } diff --git a/contracts/test/mocks/GatewayUpgradeMock.sol b/contracts/test/mocks/GatewayUpgradeMock.sol index ac660a5a96..d9fba2ef8c 100644 --- a/contracts/test/mocks/GatewayUpgradeMock.sol +++ b/contracts/test/mocks/GatewayUpgradeMock.sol @@ -11,8 +11,7 @@ import { ChannelID, MultiAddress, OriginKind, - Weight, - TransactFeeMode + Weight } from "../../src/Types.sol"; import {IGateway} from "../../src/interfaces/IGateway.sol"; import {IInitializable} from "../../src/interfaces/IInitializable.sol"; @@ -76,13 +75,12 @@ contract GatewayUpgradeMock is IGateway, IInitializable { function sendCall( ParaID destinationChain, OriginKind originKind, - TransactFeeMode feeMode, uint128 destinationFee, Weight calldata weightAtMost, bytes calldata call ) external payable {} - function quoteSendCallFee(TransactFeeMode, uint128) external pure returns (uint256) { + function quoteSendCallFee(uint128) external pure returns (uint256) { return 1; } } From 3dd1adccda2767cdfbf54a5ece51d262a437cef0 Mon Sep 17 00:00:00 2001 From: ron Date: Thu, 11 Apr 2024 10:48:41 +0800 Subject: [PATCH 26/37] Add param checks back --- contracts/src/Gateway.sol | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/contracts/src/Gateway.sol b/contracts/src/Gateway.sol index b3856ea267..086a2694c3 100644 --- a/contracts/src/Gateway.sol +++ b/contracts/src/Gateway.sol @@ -90,6 +90,7 @@ contract Gateway is IGateway, IInitializable { error InvalidCodeHash(); error InvalidConstructorParams(); error AlreadyInitialized(); + error InvalidTransact(); // handler functions are privileged modifier onlySelf() { @@ -647,6 +648,9 @@ contract Gateway is IGateway, IInitializable { Weight calldata weightAtMost, bytes calldata call ) external payable { + if (call.length == 0 || destinationFee == 0 || weightAtMost.refTime == 0 || weightAtMost.proofSize == 0) { + revert InvalidTransact(); + } bytes memory payload = SubstrateTypes.Transact(msg.sender, originKind.encode(), destinationFee, weightAtMost, call); Costs memory costs = _calculateTransactCost(destinationFee); From f07507fe0eb67a597e0e484d4f3072228c7bde3b Mon Sep 17 00:00:00 2001 From: ron Date: Thu, 11 Apr 2024 11:03:42 +0800 Subject: [PATCH 27/37] Remove script unused --- web/packages/test/scripts/configure-penpal.sh | 21 ------------------- 1 file changed, 21 deletions(-) delete mode 100755 web/packages/test/scripts/configure-penpal.sh diff --git a/web/packages/test/scripts/configure-penpal.sh b/web/packages/test/scripts/configure-penpal.sh deleted file mode 100755 index 95526accb1..0000000000 --- a/web/packages/test/scripts/configure-penpal.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env bash -set -eu - -source scripts/set-env.sh -source scripts/xcm-helper.sh - -fund_sender_sovereign() { - # forceSetBalance($sender_sovereign_account, 1000000000000) - local transact_call="0x0a0800"$sender_sovereign_account"070010a5d4e8" - send_governance_transact_from_relaychain $PENPAL_PARAID "$transact_call" -} - -configure_penpal() { - fund_sender_sovereign -} - -if [ -z "${from_start_services:-}" ]; then - echo "config penpal only!" - configure_penpal - wait -fi From 70413d80d4f636778f05ce3b53660bdf6105c91d Mon Sep 17 00:00:00 2001 From: ron Date: Thu, 11 Apr 2024 11:22:44 +0800 Subject: [PATCH 28/37] Remove the fund script not in use --- web/packages/test/scripts/configure-substrate.sh | 7 ------- web/packages/test/scripts/set-env.sh | 2 -- 2 files changed, 9 deletions(-) diff --git a/web/packages/test/scripts/configure-substrate.sh b/web/packages/test/scripts/configure-substrate.sh index 4130317c0f..c5a625d2ce 100755 --- a/web/packages/test/scripts/configure-substrate.sh +++ b/web/packages/test/scripts/configure-substrate.sh @@ -85,12 +85,6 @@ config_xcm_version() { send_governance_transact_from_relaychain $ASSET_HUB_PARAID "$call" } -fund_penpal_sender_sovereign() { - # forceSetBalance($sender_sovereign_account, 1000000000000) - local transact_call="0x0a0800"$sender_sovereign_account"070010a5d4e8" - send_governance_transact_from_relaychain $PENPAL_PARAID "$transact_call" -} - configure_substrate() { set_gateway fund_accounts @@ -98,7 +92,6 @@ configure_substrate() { config_beacon_checkpoint open_hrmp_channels config_xcm_version - fund_penpal_sender_sovereign } if [ -z "${from_start_services:-}" ]; then diff --git a/web/packages/test/scripts/set-env.sh b/web/packages/test/scripts/set-env.sh index e5a6d009e7..24015ab9b2 100755 --- a/web/packages/test/scripts/set-env.sh +++ b/web/packages/test/scripts/set-env.sh @@ -77,8 +77,6 @@ beacon_relayer_pub_key="${BEACON_RELAYER_PUB_KEY:-0xc46e141b5083721ad5f5056ba1cd execution_relayer_assethub_pub_key="${EXECUTION_RELAYER_ASSETHUB_PUB_KEY:-0x34284f0c1920694dd2e798e94e378307980d0f52d556009fc451c08bd65a8b4a}" # Execution relay account (//ExecutionRelayPenpal 5HgmfVcc8xBUcReNJsUaJMhFWGkdYpEw4RiCX4SeZPdKXR6H in testnet) execution_relayer_penpal_pub_key="${EXECUTION_RELAYER_PENPAL_PUB_KEY:-0xf8aed1861e571ef861cf34fe9587a211465aa380787e0102c2e89dfb0b666d3b}" -# Sovereign account for msg.sender in penpal (Ethereum address:0x90A987B944Cb1dCcE5564e5FDeCD7a54D3de27Fe) -sender_sovereign_account="ee99e7e8ac49f08251154c033f827541f4fb8a5b1fc4d6d9b1ab72c103bd3023" # Config for deploying contracts ## Deployment key From a364298c8249ea537522e8a078dfc6c4538a544d Mon Sep 17 00:00:00 2001 From: ron Date: Fri, 12 Apr 2024 00:07:17 +0800 Subject: [PATCH 29/37] Update relayer --- relayer/cmd/generate_beacon_data.go | 14 +++++++------- relayer/contracts/gateway.go | 26 +++++++++++++------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/relayer/cmd/generate_beacon_data.go b/relayer/cmd/generate_beacon_data.go index 66715bd4cf..27eec465d5 100644 --- a/relayer/cmd/generate_beacon_data.go +++ b/relayer/cmd/generate_beacon_data.go @@ -83,6 +83,7 @@ func generateInboundFixtureCmd() *cobra.Command { cmd.Flags().String("url", "http://127.0.0.1:9596", "Beacon URL") cmd.Flags().Uint32("nonce", 1, "Nonce of the inbound message") cmd.Flags().String("test_case", "register_token", "Inbound test case") + cmd.Flags().String("execution_relay_config", "/tmp/snowbridge/execution-relay-asset-hub.json", "Config file of execution relayer") return cmd } @@ -190,12 +191,7 @@ func generateBeaconTestFixture(cmd *cobra.Command, _ []string) error { client := api.NewBeaconClient(endpoint, conf.Source.Beacon.Spec.SlotsInEpoch) s := syncer.New(client, conf.Source.Beacon.Spec, &store) - executionRelayConfig, err := cmd.Flags().GetString("execution_relay_config") - if err != nil { - return err - } - - viper.SetConfigFile(executionRelayConfig) + viper.SetConfigFile("/tmp/snowbridge/execution-relay-asset-hub.json") if err = viper.ReadInConfig(); err != nil { return err @@ -680,7 +676,11 @@ func generateInboundFixture(cmd *cobra.Command, _ []string) error { client := api.NewBeaconClient(endpoint, conf.Source.Beacon.Spec.SlotsInEpoch) s := syncer.New(client, conf.Source.Beacon.Spec, &store) - viper.SetConfigFile("/tmp/snowbridge/execution-relay-asset-hub.json") + executionRelayConfig, err := cmd.Flags().GetString("execution_relay_config") + if err != nil { + return err + } + viper.SetConfigFile(executionRelayConfig) if err = viper.ReadInConfig(); err != nil { return err diff --git a/relayer/contracts/gateway.go b/relayer/contracts/gateway.go index 048be4e7d3..c1e6dba905 100644 --- a/relayer/contracts/gateway.go +++ b/relayer/contracts/gateway.go @@ -97,7 +97,7 @@ type Weight struct { // GatewayMetaData contains all meta data concerning the Gateway contract. var GatewayMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"function\",\"name\":\"agentOf\",\"inputs\":[{\"name\":\"agentID\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"channelNoncesOf\",\"inputs\":[{\"name\":\"channelID\",\"type\":\"bytes32\",\"internalType\":\"ChannelID\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"channelOperatingModeOf\",\"inputs\":[{\"name\":\"channelID\",\"type\":\"bytes32\",\"internalType\":\"ChannelID\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"enumOperatingMode\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"implementation\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isTokenRegistered\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"operatingMode\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"enumOperatingMode\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pricingParameters\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"UD60x18\"},{\"name\":\"\",\"type\":\"uint128\",\"internalType\":\"uint128\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"quoteRegisterTokenFee\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"quoteSendCallFee\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"quoteSendTokenFee\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"destinationChain\",\"type\":\"uint32\",\"internalType\":\"ParaID\"},{\"name\":\"destinationFee\",\"type\":\"uint128\",\"internalType\":\"uint128\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"registerToken\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"sendCall\",\"inputs\":[{\"name\":\"destinationChain\",\"type\":\"uint32\",\"internalType\":\"ParaID\"},{\"name\":\"originKind\",\"type\":\"uint8\",\"internalType\":\"enumOriginKind\"},{\"name\":\"destinationFee\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"weightAtMost\",\"type\":\"tuple\",\"internalType\":\"structWeight\",\"components\":[{\"name\":\"refTime\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"proofSize\",\"type\":\"uint64\",\"internalType\":\"uint64\"}]},{\"name\":\"call\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"sendToken\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"destinationChain\",\"type\":\"uint32\",\"internalType\":\"ParaID\"},{\"name\":\"destinationAddress\",\"type\":\"tuple\",\"internalType\":\"structMultiAddress\",\"components\":[{\"name\":\"kind\",\"type\":\"uint8\",\"internalType\":\"enumKind\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"destinationFee\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"amount\",\"type\":\"uint128\",\"internalType\":\"uint128\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"submitV1\",\"inputs\":[{\"name\":\"message\",\"type\":\"tuple\",\"internalType\":\"structInboundMessage\",\"components\":[{\"name\":\"channelID\",\"type\":\"bytes32\",\"internalType\":\"ChannelID\"},{\"name\":\"nonce\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"command\",\"type\":\"uint8\",\"internalType\":\"enumCommand\"},{\"name\":\"params\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"maxDispatchGas\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"maxFeePerGas\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"reward\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"id\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"name\":\"leafProof\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"},{\"name\":\"headerProof\",\"type\":\"tuple\",\"internalType\":\"structVerification.Proof\",\"components\":[{\"name\":\"header\",\"type\":\"tuple\",\"internalType\":\"structVerification.ParachainHeader\",\"components\":[{\"name\":\"parentHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"number\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"stateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"extrinsicsRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"digestItems\",\"type\":\"tuple[]\",\"internalType\":\"structVerification.DigestItem[]\",\"components\":[{\"name\":\"kind\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"consensusEngineID\",\"type\":\"bytes4\",\"internalType\":\"bytes4\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}]},{\"name\":\"headProof\",\"type\":\"tuple\",\"internalType\":\"structVerification.HeadProof\",\"components\":[{\"name\":\"pos\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"width\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"proof\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"}]},{\"name\":\"leafPartial\",\"type\":\"tuple\",\"internalType\":\"structVerification.MMRLeafPartial\",\"components\":[{\"name\":\"version\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"parentNumber\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"parentHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"nextAuthoritySetID\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"nextAuthoritySetLen\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"nextAuthoritySetRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"name\":\"leafProof\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"},{\"name\":\"leafProofOrder\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"AgentCreated\",\"inputs\":[{\"name\":\"agentID\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"},{\"name\":\"agent\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"AgentFundsWithdrawn\",\"inputs\":[{\"name\":\"agentID\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"recipient\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ChannelCreated\",\"inputs\":[{\"name\":\"channelID\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"ChannelID\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ChannelUpdated\",\"inputs\":[{\"name\":\"channelID\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"ChannelID\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"InboundMessageDispatched\",\"inputs\":[{\"name\":\"channelID\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"ChannelID\"},{\"name\":\"nonce\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"},{\"name\":\"messageID\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"success\",\"type\":\"bool\",\"indexed\":false,\"internalType\":\"bool\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatingModeChanged\",\"inputs\":[{\"name\":\"mode\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"enumOperatingMode\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OutboundMessageAccepted\",\"inputs\":[{\"name\":\"channelID\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"ChannelID\"},{\"name\":\"nonce\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"},{\"name\":\"messageID\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"payload\",\"type\":\"bytes\",\"indexed\":false,\"internalType\":\"bytes\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PricingParametersChanged\",\"inputs\":[],\"anonymous\":false},{\"type\":\"event\",\"name\":\"TokenRegistrationSent\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"TokenSent\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"sender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"destinationChain\",\"type\":\"uint32\",\"indexed\":true,\"internalType\":\"ParaID\"},{\"name\":\"destinationAddress\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structMultiAddress\",\"components\":[{\"name\":\"kind\",\"type\":\"uint8\",\"internalType\":\"enumKind\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"amount\",\"type\":\"uint128\",\"indexed\":false,\"internalType\":\"uint128\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"TokenTransferFeesChanged\",\"inputs\":[],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Upgraded\",\"inputs\":[{\"name\":\"implementation\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false}]", + ABI: "[{\"type\":\"function\",\"name\":\"agentOf\",\"inputs\":[{\"name\":\"agentID\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"channelNoncesOf\",\"inputs\":[{\"name\":\"channelID\",\"type\":\"bytes32\",\"internalType\":\"ChannelID\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"channelOperatingModeOf\",\"inputs\":[{\"name\":\"channelID\",\"type\":\"bytes32\",\"internalType\":\"ChannelID\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"enumOperatingMode\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"implementation\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isTokenRegistered\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"operatingMode\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"enumOperatingMode\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pricingParameters\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"UD60x18\"},{\"name\":\"\",\"type\":\"uint128\",\"internalType\":\"uint128\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"quoteRegisterTokenFee\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"quoteSendCallFee\",\"inputs\":[{\"name\":\"destinationFee\",\"type\":\"uint128\",\"internalType\":\"uint128\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"quoteSendTokenFee\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"destinationChain\",\"type\":\"uint32\",\"internalType\":\"ParaID\"},{\"name\":\"destinationFee\",\"type\":\"uint128\",\"internalType\":\"uint128\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"registerToken\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"sendCall\",\"inputs\":[{\"name\":\"destinationChain\",\"type\":\"uint32\",\"internalType\":\"ParaID\"},{\"name\":\"originKind\",\"type\":\"uint8\",\"internalType\":\"enumOriginKind\"},{\"name\":\"destinationFee\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"weightAtMost\",\"type\":\"tuple\",\"internalType\":\"structWeight\",\"components\":[{\"name\":\"refTime\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"proofSize\",\"type\":\"uint64\",\"internalType\":\"uint64\"}]},{\"name\":\"call\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"sendToken\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"destinationChain\",\"type\":\"uint32\",\"internalType\":\"ParaID\"},{\"name\":\"destinationAddress\",\"type\":\"tuple\",\"internalType\":\"structMultiAddress\",\"components\":[{\"name\":\"kind\",\"type\":\"uint8\",\"internalType\":\"enumKind\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"destinationFee\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"amount\",\"type\":\"uint128\",\"internalType\":\"uint128\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"submitV1\",\"inputs\":[{\"name\":\"message\",\"type\":\"tuple\",\"internalType\":\"structInboundMessage\",\"components\":[{\"name\":\"channelID\",\"type\":\"bytes32\",\"internalType\":\"ChannelID\"},{\"name\":\"nonce\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"command\",\"type\":\"uint8\",\"internalType\":\"enumCommand\"},{\"name\":\"params\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"maxDispatchGas\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"maxFeePerGas\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"reward\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"id\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"name\":\"leafProof\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"},{\"name\":\"headerProof\",\"type\":\"tuple\",\"internalType\":\"structVerification.Proof\",\"components\":[{\"name\":\"header\",\"type\":\"tuple\",\"internalType\":\"structVerification.ParachainHeader\",\"components\":[{\"name\":\"parentHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"number\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"stateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"extrinsicsRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"digestItems\",\"type\":\"tuple[]\",\"internalType\":\"structVerification.DigestItem[]\",\"components\":[{\"name\":\"kind\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"consensusEngineID\",\"type\":\"bytes4\",\"internalType\":\"bytes4\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}]},{\"name\":\"headProof\",\"type\":\"tuple\",\"internalType\":\"structVerification.HeadProof\",\"components\":[{\"name\":\"pos\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"width\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"proof\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"}]},{\"name\":\"leafPartial\",\"type\":\"tuple\",\"internalType\":\"structVerification.MMRLeafPartial\",\"components\":[{\"name\":\"version\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"parentNumber\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"parentHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"nextAuthoritySetID\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"nextAuthoritySetLen\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"nextAuthoritySetRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"name\":\"leafProof\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"},{\"name\":\"leafProofOrder\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"AgentCreated\",\"inputs\":[{\"name\":\"agentID\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"},{\"name\":\"agent\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"AgentFundsWithdrawn\",\"inputs\":[{\"name\":\"agentID\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"recipient\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ChannelCreated\",\"inputs\":[{\"name\":\"channelID\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"ChannelID\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ChannelUpdated\",\"inputs\":[{\"name\":\"channelID\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"ChannelID\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"InboundMessageDispatched\",\"inputs\":[{\"name\":\"channelID\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"ChannelID\"},{\"name\":\"nonce\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"},{\"name\":\"messageID\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"success\",\"type\":\"bool\",\"indexed\":false,\"internalType\":\"bool\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatingModeChanged\",\"inputs\":[{\"name\":\"mode\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"enumOperatingMode\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OutboundMessageAccepted\",\"inputs\":[{\"name\":\"channelID\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"ChannelID\"},{\"name\":\"nonce\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"},{\"name\":\"messageID\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"payload\",\"type\":\"bytes\",\"indexed\":false,\"internalType\":\"bytes\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"PricingParametersChanged\",\"inputs\":[],\"anonymous\":false},{\"type\":\"event\",\"name\":\"TokenRegistrationSent\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"TokenSent\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"sender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"destinationChain\",\"type\":\"uint32\",\"indexed\":true,\"internalType\":\"ParaID\"},{\"name\":\"destinationAddress\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structMultiAddress\",\"components\":[{\"name\":\"kind\",\"type\":\"uint8\",\"internalType\":\"enumKind\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"amount\",\"type\":\"uint128\",\"indexed\":false,\"internalType\":\"uint128\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"TokenTransferFeesChanged\",\"inputs\":[],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Upgraded\",\"inputs\":[{\"name\":\"implementation\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false}]", } // GatewayABI is the input ABI used to generate the binding from. @@ -496,12 +496,12 @@ func (_Gateway *GatewayCallerSession) QuoteRegisterTokenFee() (*big.Int, error) return _Gateway.Contract.QuoteRegisterTokenFee(&_Gateway.CallOpts) } -// QuoteSendCallFee is a free data retrieval call binding the contract method 0x1690cd14. +// QuoteSendCallFee is a free data retrieval call binding the contract method 0x9bf22c58. // -// Solidity: function quoteSendCallFee() view returns(uint256) -func (_Gateway *GatewayCaller) QuoteSendCallFee(opts *bind.CallOpts) (*big.Int, error) { +// Solidity: function quoteSendCallFee(uint128 destinationFee) view returns(uint256) +func (_Gateway *GatewayCaller) QuoteSendCallFee(opts *bind.CallOpts, destinationFee *big.Int) (*big.Int, error) { var out []interface{} - err := _Gateway.contract.Call(opts, &out, "quoteSendCallFee") + err := _Gateway.contract.Call(opts, &out, "quoteSendCallFee", destinationFee) if err != nil { return *new(*big.Int), err @@ -513,18 +513,18 @@ func (_Gateway *GatewayCaller) QuoteSendCallFee(opts *bind.CallOpts) (*big.Int, } -// QuoteSendCallFee is a free data retrieval call binding the contract method 0x1690cd14. +// QuoteSendCallFee is a free data retrieval call binding the contract method 0x9bf22c58. // -// Solidity: function quoteSendCallFee() view returns(uint256) -func (_Gateway *GatewaySession) QuoteSendCallFee() (*big.Int, error) { - return _Gateway.Contract.QuoteSendCallFee(&_Gateway.CallOpts) +// Solidity: function quoteSendCallFee(uint128 destinationFee) view returns(uint256) +func (_Gateway *GatewaySession) QuoteSendCallFee(destinationFee *big.Int) (*big.Int, error) { + return _Gateway.Contract.QuoteSendCallFee(&_Gateway.CallOpts, destinationFee) } -// QuoteSendCallFee is a free data retrieval call binding the contract method 0x1690cd14. +// QuoteSendCallFee is a free data retrieval call binding the contract method 0x9bf22c58. // -// Solidity: function quoteSendCallFee() view returns(uint256) -func (_Gateway *GatewayCallerSession) QuoteSendCallFee() (*big.Int, error) { - return _Gateway.Contract.QuoteSendCallFee(&_Gateway.CallOpts) +// Solidity: function quoteSendCallFee(uint128 destinationFee) view returns(uint256) +func (_Gateway *GatewayCallerSession) QuoteSendCallFee(destinationFee *big.Int) (*big.Int, error) { + return _Gateway.Contract.QuoteSendCallFee(&_Gateway.CallOpts, destinationFee) } // QuoteSendTokenFee is a free data retrieval call binding the contract method 0x928bc49d. From 748eea49dd47eb0204df528fb55e7e491049085c Mon Sep 17 00:00:00 2001 From: ron Date: Wed, 17 Apr 2024 12:34:44 +0800 Subject: [PATCH 30/37] Add rfc doc --- rfc/transact_from_ethereum_to_substrate.md | 47 ++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 rfc/transact_from_ethereum_to_substrate.md diff --git a/rfc/transact_from_ethereum_to_substrate.md b/rfc/transact_from_ethereum_to_substrate.md new file mode 100644 index 0000000000..4655fcd7d4 --- /dev/null +++ b/rfc/transact_from_ethereum_to_substrate.md @@ -0,0 +1,47 @@ +# RFC: Transact from Ethereum to Substrate + + +## Summary + +This RFC proposes the feature to call transact from Ethereum to Substrate through our bridge, including two PRs separately with https://github.com/Snowfork/snowbridge/pull/1141 for solidity and https://github.com/Snowfork/polkadot-sdk/pull/114 for substrate. + +## Explanation + +Basically it works as follows: + +First on Ethereum to call the transact via [sendCall](https://github.com/Snowfork/snowbridge/blob/bdf4c716c3863ad7c2a83ee870c8c399919c4e26/contracts/src/Gateway.sol#L630), the value of parameter `call` is just the scale-encoded extrinsic on substrate. + +Then on BridgeHub with [the convert logic in inbound-router](https://github.com/Snowfork/polkadot-sdk/blob/cd7a64a1ca5b8e1ea6339125c0c966065ada8e70/bridges/snowbridge/primitives/router/src/inbound/mod.rs#L337) the payload will be converted into a xcm which will be sent to the destination chain. + +Worth to note that the [BurnAsset](https://github.com/Snowfork/polkadot-sdk/blob/cd7a64a1ca5b8e1ea6339125c0c966065ada8e70/bridges/snowbridge/primitives/router/src/inbound/mod.rs#L353) in the xcm will do nothing on destination chain, included here only for the destination chain to implement a [custom Barrier](https://github.com/Snowfork/polkadot-sdk/blob/cd7a64a1ca5b8e1ea6339125c0c966065ada8e70/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs#L227) which inspect the fee as expected(i.e. can cover the transact cost to avoid spamming). + + +There is a E2E test [transact_from_ethereum_to_penpal_success](https://github.com/Snowfork/polkadot-sdk/blob/cd7a64a1ca5b8e1ea6339125c0c966065ada8e70/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs#L568) + +Check the xcm log on penpal we can see that the transact(System::remark_with_event) is executed as expected. + +``` +2024-04-17T02:59:27.224538Z TRACE xcm::process_instruction: === UnpaidExecution { weight_limit: Unlimited, check_origin: None } +2024-04-17T02:59:27.224575Z TRACE xcm::process_instruction: === BurnAsset(Assets([Asset { id: AssetId(Location { parents: 1, interior: Here }), fun: Fungible(40000000000) }])) +2024-04-17T02:59:27.224585Z TRACE xcm::process_instruction: === DescendOrigin(X1([PalletInstance(80)])) +2024-04-17T02:59:27.224610Z TRACE xcm::process_instruction: === UniversalOrigin(GlobalConsensus(Ethereum { chain_id: 11155111 })) +2024-04-17T02:59:27.224666Z TRACE xcm::process_instruction: === DescendOrigin(X1([AccountKey20 { network: None, key: [144, 169, 135, 185, 68, 203, 29, 204, 229, 86, 78, 95, 222, 205, 122, 84, 211, 222, 39, 254] }])) +2024-04-17T02:59:27.224678Z TRACE xcm::process_instruction: === Transact { origin_kind: SovereignAccount, require_weight_at_most: Weight { ref_time: 40000000, proof_size: 8000 }, call: "0x00071468656c6c6f" } +2024-04-17T02:59:27.224691Z TRACE xcm::process_instruction::transact: Processing call: RuntimeCall::System(Call::remark_with_event { remark: [104, 101, 108, 108, 111] }) +2024-04-17T02:59:27.224699Z TRACE xcm::origin_conversion: SovereignSignedViaLocation origin: Location { parents: 2, interior: X2([GlobalConsensus(Ethereum { chain_id: 11155111 }), AccountKey20 { network: None, key: [144, 169, 135, 185, 68, 203, 29, 204, 229, 86, 78, 95, 222, 205, 122, 84, 211, 222, 39, 254] }]) }, kind: SovereignAccount +2024-04-17T02:59:27.224721Z TRACE xcm::process_instruction::transact: Dispatching with origin: Origin { caller: OriginCaller::system(RawOrigin::Signed(ee99e7e8ac49f08251154c033f827541f4fb8a5b1fc4d6d9b1ab72c103bd3023 (5HTYyQW9...))), filter: "[function ptr]" } +2024-04-17T02:59:27.224828Z TRACE xcm::process_instruction::transact: Dispatch successful: PostDispatchInfo { actual_weight: None, pays_fee: Pays::Yes } +2024-04-17T02:59:27.224838Z TRACE xcm::process_instruction: === SetTopic([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]) +2024-04-17T02:59:27.224847Z TRACE xcm::execute: result: Ok(()) +``` + +## Testing, Security, and Privacy + +There is some other E2E tests + +- [transact_from_ethereum_to_penpal_insufficient_weight](https://github.com/Snowfork/polkadot-sdk/blob/cd7a64a1ca5b8e1ea6339125c0c966065ada8e70/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs#L624) + +- [transact_from_ethereum_to_penpal_insufficient_fee](https://github.com/Snowfork/polkadot-sdk/blob/cd7a64a1ca5b8e1ea6339125c0c966065ada8e70/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs#L665C4-L665C53) + +which demonstrates the [custom Barrier](https://github.com/Snowfork/polkadot-sdk/blob/cd7a64a1ca5b8e1ea6339125c0c966065ada8e70/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs#L227) on penpal can check the fee to cover the transact cost. + From e27c0eb93451c5865b4aaa817c693892f8b54e53 Mon Sep 17 00:00:00 2001 From: ron Date: Wed, 17 Apr 2024 22:25:18 +0800 Subject: [PATCH 31/37] Ignore destination fee for the transact --- contracts/src/Gateway.sol | 4 ++-- contracts/test/Gateway.t.sol | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/contracts/src/Gateway.sol b/contracts/src/Gateway.sol index ea6cab493c..302c9dbb7d 100644 --- a/contracts/src/Gateway.sol +++ b/contracts/src/Gateway.sol @@ -622,8 +622,8 @@ contract Gateway is IGateway, IInitializable, IUpgradable { } // Calculate cost for transact - function _calculateTransactCost(uint128 destinationFee) internal pure returns (Costs memory costs) { - return Costs({native: 0, foreign: destinationFee}); + function _calculateTransactCost(uint128) internal pure returns (Costs memory costs) { + return Costs({native: 0, foreign: 0}); } /// @inheritdoc IGateway diff --git a/contracts/test/Gateway.t.sol b/contracts/test/Gateway.t.sol index f6f4d4e563..61daa67e50 100644 --- a/contracts/test/Gateway.t.sol +++ b/contracts/test/Gateway.t.sol @@ -896,7 +896,7 @@ contract GatewayTest is Test { bytes memory payload = SubstrateTypes.Transact(account1, 0x01, 1, Weight(1, 1), bytes("0x1")); console.logBytes(payload); uint256 fee = IGateway(address(gateway)).quoteSendCallFee(1); - assertEq(fee, 2500000000250000); + assertEq(fee, 2500000000000000); vm.expectEmit(true, false, false, true); emit IGateway.OutboundMessageAccepted(penpalParaID.into(), 1, messageID, payload); hoax(address(account1)); @@ -907,6 +907,6 @@ contract GatewayTest is Test { function testQuoteSendCallFee() public { uint256 fee = IGateway(address(gateway)).quoteSendCallFee(1); - assertEq(fee, 2500000000250000); + assertEq(fee, 2500000000000000); } } From e5c1a70ab76a87158457e9cdf45f81f7e7bb15a3 Mon Sep 17 00:00:00 2001 From: ron Date: Mon, 22 Apr 2024 15:46:02 +0800 Subject: [PATCH 32/37] Update rfc --- rfc/transact_from_ethereum_to_substrate.md | 27 ++++++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/rfc/transact_from_ethereum_to_substrate.md b/rfc/transact_from_ethereum_to_substrate.md index 4655fcd7d4..416e7ffa34 100644 --- a/rfc/transact_from_ethereum_to_substrate.md +++ b/rfc/transact_from_ethereum_to_substrate.md @@ -11,12 +11,24 @@ Basically it works as follows: First on Ethereum to call the transact via [sendCall](https://github.com/Snowfork/snowbridge/blob/bdf4c716c3863ad7c2a83ee870c8c399919c4e26/contracts/src/Gateway.sol#L630), the value of parameter `call` is just the scale-encoded extrinsic on substrate. -Then on BridgeHub with [the convert logic in inbound-router](https://github.com/Snowfork/polkadot-sdk/blob/cd7a64a1ca5b8e1ea6339125c0c966065ada8e70/bridges/snowbridge/primitives/router/src/inbound/mod.rs#L337) the payload will be converted into a xcm which will be sent to the destination chain. +Then on BridgeHub with [the convert logic in inbound-router](https://github.com/Snowfork/polkadot-sdk/blob/1cab94c80aefdf3497d69828a22ac15bd27dbb95/bridges/snowbridge/primitives/router/src/inbound/mod.rs#L341) the payload will be converted into a [xcm](https://github.com/Snowfork/polkadot-sdk/blob/1cab94c80aefdf3497d69828a22ac15bd27dbb95/bridges/snowbridge/primitives/router/src/inbound/mod.rs#L359-L370) which will be sent to the destination chain. -Worth to note that the [BurnAsset](https://github.com/Snowfork/polkadot-sdk/blob/cd7a64a1ca5b8e1ea6339125c0c966065ada8e70/bridges/snowbridge/primitives/router/src/inbound/mod.rs#L353) in the xcm will do nothing on destination chain, included here only for the destination chain to implement a [custom Barrier](https://github.com/Snowfork/polkadot-sdk/blob/cd7a64a1ca5b8e1ea6339125c0c966065ada8e70/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs#L227) which inspect the fee as expected(i.e. can cover the transact cost to avoid spamming). +There is a E2E test [transact_from_ethereum_to_penpal_success](https://github.com/Snowfork/polkadot-sdk/blob/cd7a64a1ca5b8e1ea6339125c0c966065ada8e70/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs#L568) + +The xcm forwarded to destination chain is: + +``` +instructions: [ + DescendOrigin(X1([PalletInstance(80)])), + UniversalOrigin(GlobalConsensus(Ethereum { chain_id: 11155111 })), + DescendOrigin(X1([AccountKey20 { network: None, key: [238, 145, 112, 171, 251, 249, 66, 26, 214, 221, 7, 246, 189, 236, 157, 137, 242, 181, 129, 224] }])), + WithdrawAsset(Assets([Asset { id: AssetId(Location { parents: 0, interior: Here }), fun: Fungible(40000000000) }])), + BuyExecution { fees: Asset { id: AssetId(Location { parents: 0, interior: Here }), fun: Fungible(40000000000) }, weight_limit: Unlimited }, + Transact { origin_kind: SovereignAccount, require_weight_at_most: Weight { ref_time: 40000000, proof_size: 8000 }, call: "0x00071468656c6c6f" } +] +``` -There is a E2E test [transact_from_ethereum_to_penpal_success](https://github.com/Snowfork/polkadot-sdk/blob/cd7a64a1ca5b8e1ea6339125c0c966065ada8e70/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs#L568) Check the xcm log on penpal we can see that the transact(System::remark_with_event) is executed as expected. @@ -35,6 +47,13 @@ Check the xcm log on penpal we can see that the transact(System::remark_with_eve 2024-04-17T02:59:27.224847Z TRACE xcm::execute: result: Ok(()) ``` +### Fee Flow + + +| Ethereum | Bridgehub | Penpal +|----------|:-------------:|------: +|Charge from end user to the agent of penpal with fee in Ether | Refund the relayer from sovereign of penpal in DOT | `BuyExecution` with fee paid by a pre-funded sovereign account of the Ethereum user who initiated the bridging operation. With `destination_fee` in native token + ## Testing, Security, and Privacy There is some other E2E tests @@ -43,5 +62,3 @@ There is some other E2E tests - [transact_from_ethereum_to_penpal_insufficient_fee](https://github.com/Snowfork/polkadot-sdk/blob/cd7a64a1ca5b8e1ea6339125c0c966065ada8e70/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs#L665C4-L665C53) -which demonstrates the [custom Barrier](https://github.com/Snowfork/polkadot-sdk/blob/cd7a64a1ca5b8e1ea6339125c0c966065ada8e70/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs#L227) on penpal can check the fee to cover the transact cost. - From 53791d223ea0ef227aa1d89d345c20f583afa3ad Mon Sep 17 00:00:00 2001 From: ron Date: Mon, 22 Apr 2024 22:25:32 +0800 Subject: [PATCH 33/37] Update rfc with fee section --- rfc/transact_from_ethereum_to_substrate.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/rfc/transact_from_ethereum_to_substrate.md b/rfc/transact_from_ethereum_to_substrate.md index 416e7ffa34..ef5334716f 100644 --- a/rfc/transact_from_ethereum_to_substrate.md +++ b/rfc/transact_from_ethereum_to_substrate.md @@ -47,12 +47,17 @@ Check the xcm log on penpal we can see that the transact(System::remark_with_eve 2024-04-17T02:59:27.224847Z TRACE xcm::execute: result: Ok(()) ``` -### Fee Flow +## Fee Flow +- dApp is represents `msg.sender` or its sovereign depending on context. +- Parachain represents the target parachain, its sovereign or its agent depending on context. -| Ethereum | Bridgehub | Penpal -|----------|:-------------:|------: -|Charge from end user to the agent of penpal with fee in Ether | Refund the relayer from sovereign of penpal in DOT | `BuyExecution` with fee paid by a pre-funded sovereign account of the Ethereum user who initiated the bridging operation. With `destination_fee` in native token +Sequence|Where|Who|What +-|-|-|- +1|Gateway|dApp|pays(ETH, converted to DOT here) Parachain Agent for delivery costs only (no execution cost) +2|Bridge Hub|Relayer|pays(DOT) node for execution +3|Bridge Hub|Parachain Sovereign|pays(DOT) Relayer for delivery (refund+reward) +4|Parachain|dApp|pays(DOT, Native) for execution only. ## Testing, Security, and Privacy From 61d5ea5688072fe4b4d1b4a81d4e8c2ac558c5cc Mon Sep 17 00:00:00 2001 From: ron Date: Wed, 24 Apr 2024 16:11:25 +0800 Subject: [PATCH 34/37] Cleanup --- contracts/src/Gateway.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/src/Gateway.sol b/contracts/src/Gateway.sol index 302c9dbb7d..d69e27a734 100644 --- a/contracts/src/Gateway.sol +++ b/contracts/src/Gateway.sol @@ -622,7 +622,7 @@ contract Gateway is IGateway, IInitializable, IUpgradable { } // Calculate cost for transact - function _calculateTransactCost(uint128) internal pure returns (Costs memory costs) { + function _calculateTransactCost() internal pure returns (Costs memory costs) { return Costs({native: 0, foreign: 0}); } @@ -639,14 +639,14 @@ contract Gateway is IGateway, IInitializable, IUpgradable { } bytes memory payload = SubstrateTypes.Transact(msg.sender, originKind.encode(), destinationFee, weightAtMost, call); - Costs memory costs = _calculateTransactCost(destinationFee); + Costs memory costs = _calculateTransactCost(); Ticket memory ticket = Ticket({dest: destinationChain, costs: costs, payload: payload}); _submitOutbound(ticket); } /// @inheritdoc IGateway function quoteSendCallFee(uint128 destinationFee) external view returns (uint256) { - Costs memory costs = _calculateTransactCost(destinationFee); + Costs memory costs = _calculateTransactCost(); return _calculateFee(costs); } } From b935ca8246b9825b6cc35ef19f00a19a042d4b55 Mon Sep 17 00:00:00 2001 From: ron Date: Mon, 29 Apr 2024 14:22:22 +0800 Subject: [PATCH 35/37] Update rfc doc --- rfc/transact_from_ethereum_to_substrate.md | 37 +++++++--------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/rfc/transact_from_ethereum_to_substrate.md b/rfc/transact_from_ethereum_to_substrate.md index ef5334716f..d0b738233b 100644 --- a/rfc/transact_from_ethereum_to_substrate.md +++ b/rfc/transact_from_ethereum_to_substrate.md @@ -3,18 +3,23 @@ ## Summary -This RFC proposes the feature to call transact from Ethereum to Substrate through our bridge, including two PRs separately with https://github.com/Snowfork/snowbridge/pull/1141 for solidity and https://github.com/Snowfork/polkadot-sdk/pull/114 for substrate. +This RFC proposes the feature to call transact from Ethereum to Substrate through our bridge, including two PRs separately. + +- https://github.com/Snowfork/snowbridge/pull/1141 for solidity +- https://github.com/Snowfork/polkadot-sdk/pull/114 for substrate. ## Explanation Basically it works as follows: -First on Ethereum to call the transact via [sendCall](https://github.com/Snowfork/snowbridge/blob/bdf4c716c3863ad7c2a83ee870c8c399919c4e26/contracts/src/Gateway.sol#L630), the value of parameter `call` is just the scale-encoded extrinsic on substrate. +First on Ethereum to call the transact via [sendCall](https://github.com/Snowfork/snowbridge/blob/dfa331d9de5b2fa4d76fdd0edc00667a6f21b4bf/contracts/src/Gateway.sol#L630), the value of parameter `call` is just the scale-encoded extrinsic on substrate. -Then on BridgeHub with [the convert logic in inbound-router](https://github.com/Snowfork/polkadot-sdk/blob/1cab94c80aefdf3497d69828a22ac15bd27dbb95/bridges/snowbridge/primitives/router/src/inbound/mod.rs#L341) the payload will be converted into a [xcm](https://github.com/Snowfork/polkadot-sdk/blob/1cab94c80aefdf3497d69828a22ac15bd27dbb95/bridges/snowbridge/primitives/router/src/inbound/mod.rs#L359-L370) which will be sent to the destination chain. +Worth to note that on Ethereum we charge only for the delivery cost on BH, not including the execution cost on destination chain(i.e. `remote_fee` marked as [zero](https://github.com/Snowfork/snowbridge/blob/dfa331d9de5b2fa4d76fdd0edc00667a6f21b4bf/contracts/src/Gateway.sol#L625)) +Then on BridgeHub with [the convert logic in inbound-router](https://github.com/Snowfork/polkadot-sdk/blob/9829de7a0e12816c96c820b91abe195af8486269/bridges/snowbridge/primitives/router/src/inbound/mod.rs#L342) the payload will be converted into a [xcm](https://github.com/Snowfork/polkadot-sdk/blob/9829de7a0e12816c96c820b91abe195af8486269/bridges/snowbridge/primitives/router/src/inbound/mod.rs#L356-L368) which will be sent to the destination chain. -There is a E2E test [transact_from_ethereum_to_penpal_success](https://github.com/Snowfork/polkadot-sdk/blob/cd7a64a1ca5b8e1ea6339125c0c966065ada8e70/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs#L568) + +There is a E2E test [transact_from_ethereum_to_penpal_success](https://github.com/Snowfork/polkadot-sdk/blob/9829de7a0e12816c96c820b91abe195af8486269/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs#L572) The xcm forwarded to destination chain is: @@ -29,24 +34,6 @@ instructions: [ ] ``` - -Check the xcm log on penpal we can see that the transact(System::remark_with_event) is executed as expected. - -``` -2024-04-17T02:59:27.224538Z TRACE xcm::process_instruction: === UnpaidExecution { weight_limit: Unlimited, check_origin: None } -2024-04-17T02:59:27.224575Z TRACE xcm::process_instruction: === BurnAsset(Assets([Asset { id: AssetId(Location { parents: 1, interior: Here }), fun: Fungible(40000000000) }])) -2024-04-17T02:59:27.224585Z TRACE xcm::process_instruction: === DescendOrigin(X1([PalletInstance(80)])) -2024-04-17T02:59:27.224610Z TRACE xcm::process_instruction: === UniversalOrigin(GlobalConsensus(Ethereum { chain_id: 11155111 })) -2024-04-17T02:59:27.224666Z TRACE xcm::process_instruction: === DescendOrigin(X1([AccountKey20 { network: None, key: [144, 169, 135, 185, 68, 203, 29, 204, 229, 86, 78, 95, 222, 205, 122, 84, 211, 222, 39, 254] }])) -2024-04-17T02:59:27.224678Z TRACE xcm::process_instruction: === Transact { origin_kind: SovereignAccount, require_weight_at_most: Weight { ref_time: 40000000, proof_size: 8000 }, call: "0x00071468656c6c6f" } -2024-04-17T02:59:27.224691Z TRACE xcm::process_instruction::transact: Processing call: RuntimeCall::System(Call::remark_with_event { remark: [104, 101, 108, 108, 111] }) -2024-04-17T02:59:27.224699Z TRACE xcm::origin_conversion: SovereignSignedViaLocation origin: Location { parents: 2, interior: X2([GlobalConsensus(Ethereum { chain_id: 11155111 }), AccountKey20 { network: None, key: [144, 169, 135, 185, 68, 203, 29, 204, 229, 86, 78, 95, 222, 205, 122, 84, 211, 222, 39, 254] }]) }, kind: SovereignAccount -2024-04-17T02:59:27.224721Z TRACE xcm::process_instruction::transact: Dispatching with origin: Origin { caller: OriginCaller::system(RawOrigin::Signed(ee99e7e8ac49f08251154c033f827541f4fb8a5b1fc4d6d9b1ab72c103bd3023 (5HTYyQW9...))), filter: "[function ptr]" } -2024-04-17T02:59:27.224828Z TRACE xcm::process_instruction::transact: Dispatch successful: PostDispatchInfo { actual_weight: None, pays_fee: Pays::Yes } -2024-04-17T02:59:27.224838Z TRACE xcm::process_instruction: === SetTopic([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]) -2024-04-17T02:59:27.224847Z TRACE xcm::execute: result: Ok(()) -``` - ## Fee Flow - dApp is represents `msg.sender` or its sovereign depending on context. @@ -61,9 +48,9 @@ Sequence|Where|Who|What ## Testing, Security, and Privacy -There is some other E2E tests +Some other E2E tests for edge cases: -- [transact_from_ethereum_to_penpal_insufficient_weight](https://github.com/Snowfork/polkadot-sdk/blob/cd7a64a1ca5b8e1ea6339125c0c966065ada8e70/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs#L624) +- [transact_from_ethereum_to_penpal_insufficient_weight](https://github.com/Snowfork/polkadot-sdk/blob/9829de7a0e12816c96c820b91abe195af8486269/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs#L637) -- [transact_from_ethereum_to_penpal_insufficient_fee](https://github.com/Snowfork/polkadot-sdk/blob/cd7a64a1ca5b8e1ea6339125c0c966065ada8e70/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs#L665C4-L665C53) +- [transact_from_ethereum_to_penpal_insufficient_fee](https://github.com/Snowfork/polkadot-sdk/blob/9829de7a0e12816c96c820b91abe195af8486269/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs#L679) From 28477512b21a8a777cd4d5cedd86337cbf0e7375 Mon Sep 17 00:00:00 2001 From: ron Date: Sun, 5 May 2024 23:02:41 +0800 Subject: [PATCH 36/37] Update rfc --- rfc/transact_from_ethereum_to_substrate.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rfc/transact_from_ethereum_to_substrate.md b/rfc/transact_from_ethereum_to_substrate.md index d0b738233b..5dae50dde8 100644 --- a/rfc/transact_from_ethereum_to_substrate.md +++ b/rfc/transact_from_ethereum_to_substrate.md @@ -4,7 +4,7 @@ ## Summary This RFC proposes the feature to call transact from Ethereum to Substrate through our bridge, including two PRs separately. - + - https://github.com/Snowfork/snowbridge/pull/1141 for solidity - https://github.com/Snowfork/polkadot-sdk/pull/114 for substrate. @@ -34,6 +34,8 @@ instructions: [ ] ``` +Worth to note that it’s a pre-funded account which represents sovereign of msg.sender to pay fo the execution cost on destination chain. + ## Fee Flow - dApp is represents `msg.sender` or its sovereign depending on context. From bfdff266ac2acac0a39be8f3f82897a427b1dd72 Mon Sep 17 00:00:00 2001 From: ron Date: Sun, 5 May 2024 23:04:09 +0800 Subject: [PATCH 37/37] Remove unused destinationFee --- contracts/src/Gateway.sol | 2 +- contracts/src/interfaces/IGateway.sol | 2 +- contracts/test/Gateway.t.sol | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/contracts/src/Gateway.sol b/contracts/src/Gateway.sol index d69e27a734..2e14ef668e 100644 --- a/contracts/src/Gateway.sol +++ b/contracts/src/Gateway.sol @@ -645,7 +645,7 @@ contract Gateway is IGateway, IInitializable, IUpgradable { } /// @inheritdoc IGateway - function quoteSendCallFee(uint128 destinationFee) external view returns (uint256) { + function quoteSendCallFee() external view returns (uint256) { Costs memory costs = _calculateTransactCost(); return _calculateFee(costs); } diff --git a/contracts/src/interfaces/IGateway.sol b/contracts/src/interfaces/IGateway.sol index aa7b0185f9..948cfd26eb 100644 --- a/contracts/src/interfaces/IGateway.sol +++ b/contracts/src/interfaces/IGateway.sol @@ -113,5 +113,5 @@ interface IGateway { ) external payable; /// @dev Quote a fee in Ether for transact - function quoteSendCallFee(uint128 destinationFee) external view returns (uint256); + function quoteSendCallFee() external view returns (uint256); } diff --git a/contracts/test/Gateway.t.sol b/contracts/test/Gateway.t.sol index 86c08ad3b1..538da8c73a 100644 --- a/contracts/test/Gateway.t.sol +++ b/contracts/test/Gateway.t.sol @@ -895,7 +895,7 @@ contract GatewayTest is Test { function testTransactFromSovereignAccountWithFee() public { bytes memory payload = SubstrateTypes.Transact(account1, 0x01, 1, Weight(1, 1), bytes("0x1")); console.logBytes(payload); - uint256 fee = IGateway(address(gateway)).quoteSendCallFee(1); + uint256 fee = IGateway(address(gateway)).quoteSendCallFee(); assertEq(fee, 2500000000000000); vm.expectEmit(true, false, false, true); emit IGateway.OutboundMessageAccepted(penpalParaID.into(), 1, messageID, payload); @@ -906,7 +906,7 @@ contract GatewayTest is Test { } function testQuoteSendCallFee() public { - uint256 fee = IGateway(address(gateway)).quoteSendCallFee(1); + uint256 fee = IGateway(address(gateway)).quoteSendCallFee(); assertEq(fee, 2500000000000000); } }