From bb91e656888a9d2c95b02dbf5aada87d236ec043 Mon Sep 17 00:00:00 2001 From: Vincent Geddes Date: Tue, 21 Nov 2023 19:06:01 +0200 Subject: [PATCH 01/38] Gateway should provide detailed fee info --- contracts/src/AgentExecutor.sol | 4 +--- contracts/src/Assets.sol | 21 ++++++++++++++++++--- contracts/src/Gateway.sol | 19 +++++++++++++------ contracts/src/interfaces/IGateway.sol | 11 +++++++++-- contracts/test/Gateway.t.sol | 12 +++++------- contracts/test/mocks/GatewayUpgradeMock.sol | 13 +++++++++---- 6 files changed, 55 insertions(+), 25 deletions(-) diff --git a/contracts/src/AgentExecutor.sol b/contracts/src/AgentExecutor.sol index df8145bed6..557ed23b77 100644 --- a/contracts/src/AgentExecutor.sol +++ b/contracts/src/AgentExecutor.sol @@ -17,8 +17,7 @@ contract AgentExecutor { /// @dev Execute a message which originated from the Polkadot side of the bridge. In other terms, /// the `data` parameter is constructed by the BridgeHub parachain. /// - /// NOTE: There are no authorization checks here. Since this contract is only used for its code. - function execute(address, bytes memory data) external { + function execute(bytes memory data) external { (AgentExecuteCommand command, bytes memory params) = abi.decode(data, (AgentExecuteCommand, bytes)); if (command == AgentExecuteCommand.TransferToken) { (address token, address recipient, uint128 amount) = abi.decode(params, (address, address, uint128)); @@ -29,7 +28,6 @@ contract AgentExecutor { /// @dev Transfer ether to `recipient`. Unlike `_transferToken` This logic is not nested within `execute`, /// as the gateway needs to control an agent's ether balance directly. /// - /// NOTE: There are no authorization checks here. Since this contract is only used for its code. function transferNative(address payable recipient, uint256 amount) external { recipient.safeNativeTransfer(amount); } diff --git a/contracts/src/Assets.sol b/contracts/src/Assets.sol index e50d94e938..9c77f0129f 100644 --- a/contracts/src/Assets.sol +++ b/contracts/src/Assets.sol @@ -24,11 +24,11 @@ library Assets { error Unsupported(); // This library requires state which must be initialized in the gateway's storage. - function initialize(uint256 registerTokenFee, uint256 sendTokenFee) external { + function initialize(uint256 _registerTokenFee, uint256 _sendTokenFee) external { AssetsStorage.Layout storage $ = AssetsStorage.layout(); - $.registerTokenFee = registerTokenFee; - $.sendTokenFee = sendTokenFee; + $.registerTokenFee = _registerTokenFee; + $.sendTokenFee = _sendTokenFee; } /// @dev transfer tokens from the sender to the specified @@ -44,6 +44,16 @@ library Assets { IERC20(token).safeTransferFrom(sender, assetHubAgent, amount); } + function sendTokenFee(ParaID assetHubParaID, ParaID destinationChain) external view returns (uint256) { + AssetsStorage.Layout storage $ = AssetsStorage.layout(); + if (assetHubParaID == destinationChain) { + return $.sendTokenFee; + } + // If the final destination chain is not AssetHub, we need to add to the costs + // an extra XCM message to the destination + return 2 * $.sendTokenFee; + } + function sendToken( ParaID assetHubParaID, address assetHubAgent, @@ -81,6 +91,11 @@ library Assets { emit IGateway.TokenSent(sender, token, destinationChain, destinationAddress, amount); } + function registerTokenFee() external view returns (uint256) { + AssetsStorage.Layout storage $ = AssetsStorage.layout(); + return $.registerTokenFee; + } + /// @dev Enqueues a create native token message to substrate. /// @param token The ERC20 token address. function registerToken(address token) external returns (bytes memory payload, uint256 extraFee) { diff --git a/contracts/src/Gateway.sol b/contracts/src/Gateway.sol index e0652e7310..7e4821bdff 100644 --- a/contracts/src/Gateway.sol +++ b/contracts/src/Gateway.sol @@ -238,11 +238,6 @@ contract Gateway is IGateway, IInitializable { return ERC1967.load(); } - function tokenTransferFees() external view returns (uint256, uint256) { - AssetsStorage.Layout storage $ = AssetsStorage.layout(); - return ($.registerTokenFee, $.sendTokenFee); - } - /** * Handlers */ @@ -262,7 +257,7 @@ contract Gateway is IGateway, IInitializable { revert InvalidAgentExecutionPayload(); } - bytes memory call = abi.encodeCall(AgentExecutor.execute, (address(this), params.payload)); + bytes memory call = abi.encodeCall(AgentExecutor.execute, params.payload); (bool success, bytes memory returndata) = Agent(payable(agent)).invoke(AGENT_EXECUTOR, call); if (!success) { @@ -444,6 +439,12 @@ contract Gateway is IGateway, IInitializable { * Assets */ + // Total fee for registering a token + function registerTokenFee() external view returns (uint256, uint256) { + Channel storage channel = _ensureChannel(ASSET_HUB_PARA_ID.into()); + return (channel.outboundFee, Assets.registerTokenFee()); + } + // Register a token on AssetHub function registerToken(address token) external payable { (bytes memory payload, uint256 extraFee) = Assets.registerToken(token); @@ -451,6 +452,12 @@ contract Gateway is IGateway, IInitializable { _submitOutbound(ASSET_HUB_PARA_ID, payload, extraFee); } + // Total fee for sending a token + function sendTokenFee(address, ParaID destinationChain) external view returns (uint256, uint256) { + Channel storage channel = _ensureChannel(ASSET_HUB_PARA_ID.into()); + return (channel.outboundFee, Assets.sendTokenFee(ASSET_HUB_PARA_ID, destinationChain)); + } + // Transfer ERC20 tokens to a Polkadot parachain function sendToken(address token, ParaID destinationChain, MultiAddress calldata destinationAddress, uint128 amount) external diff --git a/contracts/src/interfaces/IGateway.sol b/contracts/src/interfaces/IGateway.sol index d36e4a2393..a4ba7a5499 100644 --- a/contracts/src/interfaces/IGateway.sol +++ b/contracts/src/interfaces/IGateway.sol @@ -75,13 +75,20 @@ interface IGateway { /// @dev Emitted when a command is sent to register a new wrapped token on AssetHub event TokenRegistrationSent(address token); - // @dev Fees in Ether for registering and sending tokens respectively - function tokenTransferFees() external view returns (uint256, uint256); + /// @dev Fee schedule in Ether for registering a token, covering + /// 1. Delivery costs to BridgeHub + /// 2. XCM Execution costs on AssetHub + function registerTokenFee() external view returns (uint256, uint256); /// @dev Send a message to the AssetHub parachain to register a new fungible asset /// in the `ForeignAssets` pallet. function registerToken(address token) external payable; + /// @dev Fees in Ether for sending a token + /// 1. Delivery costs to BridgeHub + /// 2. XCM execution costs on destinationChain + function sendTokenFee(address token, ParaID destinationChain) external view returns (uint256, uint256); + /// @dev Send ERC20 tokens to parachain `destinationChain` and deposit into account `destinationAddress` function sendToken(address token, ParaID destinationChain, MultiAddress calldata destinationAddress, uint128 amount) external diff --git a/contracts/test/Gateway.t.sol b/contracts/test/Gateway.t.sol index 7ca5442eea..9e7de3a10d 100644 --- a/contracts/test/Gateway.t.sol +++ b/contracts/test/Gateway.t.sol @@ -760,15 +760,13 @@ contract GatewayTest is Test { } function testSetTokenFees() public { - (uint256 register, uint256 send) = IGateway(address(gateway)).tokenTransferFees(); - assertEq(register, 1 ether); - assertEq(send, 1 ether); + (, uint256 fee) = IGateway(address(gateway)).registerTokenFee(); + assertEq(fee, 1 ether); GatewayMock(address(gateway)).setTokenTransferFeesPublic( - abi.encode(Gateway.SetTokenTransferFeesParams({register: 1, send: 1})) + abi.encode(Gateway.SetTokenTransferFeesParams({register: 2, send: 1})) ); - (register, send) = IGateway(address(gateway)).tokenTransferFees(); - assertEq(register, 1); - assertEq(send, 1); + (, fee) = IGateway(address(gateway)).registerTokenFee(); + assertEq(fee, 2); } bytes32 public expectChannelIDBytes = bytes32(0xc173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539); diff --git a/contracts/test/mocks/GatewayUpgradeMock.sol b/contracts/test/mocks/GatewayUpgradeMock.sol index 760be21c05..1beefa2bf4 100644 --- a/contracts/test/mocks/GatewayUpgradeMock.sol +++ b/contracts/test/mocks/GatewayUpgradeMock.sol @@ -32,17 +32,22 @@ contract GatewayUpgradeMock is IGateway, IInitializable { return address(0); } - function tokenTransferFees() external pure returns (uint256, uint256) { - return (1, 1); - } - function implementation() external pure returns (address) { return address(0); } function submitInbound(InboundMessage calldata, bytes32[] calldata, Verification.Proof calldata) external {} + function registerTokenFee() external pure returns (uint256, uint256) { + return (1, 1); + } + function registerToken(address) external payable {} + + function sendTokenFee(address, ParaID) external pure returns (uint256, uint256) { + return (1, 1); + } + function sendToken(address, ParaID, MultiAddress calldata, uint128) external payable {} event Initialized(uint256 d0, uint256 d1); From 5d80c41221926c9e7a428f8049f96fc78dd81217 Mon Sep 17 00:00:00 2001 From: Vincent Geddes Date: Wed, 22 Nov 2023 15:33:36 +0200 Subject: [PATCH 02/38] Fix tests --- contracts/src/Assets.sol | 10 +++++++--- contracts/test/Gateway.t.sol | 24 ++++++++++++++++++------ 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/contracts/src/Assets.sol b/contracts/src/Assets.sol index 9c77f0129f..16ff1e26e4 100644 --- a/contracts/src/Assets.sol +++ b/contracts/src/Assets.sol @@ -49,8 +49,8 @@ library Assets { if (assetHubParaID == destinationChain) { return $.sendTokenFee; } - // If the final destination chain is not AssetHub, we need to add to the costs - // an extra XCM message to the destination + // If the final destination chain is not AssetHub, then the fee needs to additionally + // include the cost of executing an XCM on the final destination parachain. return 2 * $.sendTokenFee; } @@ -71,8 +71,10 @@ library Assets { if (destinationAddress.isAddress32()) { payload = SubstrateTypes.SendTokenToAssetHubAddress32(token, destinationAddress.asAddress32(), amount); } else { + // AssetHub does not support 20-byte account IDs revert Unsupported(); } + extraFee = $.sendTokenFee; } else { if (destinationAddress.isAddress32()) { payload = SubstrateTypes.SendTokenToAddress32( @@ -85,8 +87,10 @@ library Assets { } else { revert Unsupported(); } + // If the final destination chain is not AssetHub, then the fee needs to additionally + // include the cost of executing an XCM on the final destination parachain. + extraFee = 2 * $.sendTokenFee; } - extraFee = $.sendTokenFee; emit IGateway.TokenSent(sender, token, destinationChain, destinationAddress, amount); } diff --git a/contracts/test/Gateway.t.sol b/contracts/test/Gateway.t.sol index 9e7de3a10d..de3a731253 100644 --- a/contracts/test/Gateway.t.sol +++ b/contracts/test/Gateway.t.sol @@ -276,14 +276,17 @@ contract GatewayTest is Test { address user = makeAddr("user"); deal(address(token), user, 1); + (uint256 bridgeFee, uint256 xcmFee) = IGateway(address(gateway)).sendTokenFee(address(token), ParaID.wrap(0)); + uint256 totalFee = bridgeFee + xcmFee; + // Let gateway lock up to 1 tokens hoax(user); token.approve(address(gateway), 1); - hoax(user, 2 ether); - IGateway(address(gateway)).sendToken{value: 2 ether}(address(token), ParaID.wrap(0), recipientAddress32, 1); + hoax(user, totalFee); + IGateway(address(gateway)).sendToken{value: totalFee}(address(token), ParaID.wrap(0), recipientAddress32, 1); - assertEq(user.balance, 0 ether); + assertEq(user.balance, 0); } // User doesn't have enough funds to send message @@ -581,6 +584,9 @@ contract GatewayTest is Test { // Multilocation for recipient ParaID destPara = ParaID.wrap(2043); + (uint256 bridgeFee, uint256 xcmFee) = IGateway(address(gateway)).sendTokenFee(address(token), destPara); + uint256 totalFee = bridgeFee + xcmFee; + vm.expectEmit(true, true, false, true); emit IGateway.TokenSent(address(this), address(token), destPara, recipientAddress32, 1); @@ -588,7 +594,7 @@ contract GatewayTest is Test { vm.expectEmit(true, false, false, false); emit IGateway.OutboundMessageAccepted(assetHubParaID.into(), 1, messageID, bytes("")); - IGateway(address(gateway)).sendToken{value: 2 ether}(address(token), destPara, recipientAddress32, 1); + IGateway(address(gateway)).sendToken{value: totalFee}(address(token), destPara, recipientAddress32, 1); } function testSendTokenAddress32ToAssetHub() public { @@ -598,6 +604,9 @@ contract GatewayTest is Test { // Multilocation for recipient ParaID destPara = assetHubParaID; + (uint256 bridgeFee, uint256 xcmFee) = IGateway(address(gateway)).sendTokenFee(address(token), destPara); + uint256 totalFee = bridgeFee + xcmFee; + vm.expectEmit(true, true, false, true); emit IGateway.TokenSent(address(this), address(token), destPara, recipientAddress32, 1); @@ -605,7 +614,7 @@ contract GatewayTest is Test { vm.expectEmit(true, false, false, false); emit IGateway.OutboundMessageAccepted(assetHubParaID.into(), 1, messageID, bytes("")); - IGateway(address(gateway)).sendToken{value: 2 ether}(address(token), destPara, recipientAddress32, 1); + IGateway(address(gateway)).sendToken{value: totalFee}(address(token), destPara, recipientAddress32, 1); } function testSendTokenAddress20() public { @@ -615,6 +624,9 @@ contract GatewayTest is Test { // Multilocation for recipient ParaID destPara = ParaID.wrap(2043); + (uint256 bridgeFee, uint256 xcmFee) = IGateway(address(gateway)).sendTokenFee(address(token), destPara); + uint256 totalFee = bridgeFee + xcmFee; + vm.expectEmit(true, true, false, true); emit IGateway.TokenSent(address(this), address(token), destPara, recipientAddress20, 1); @@ -622,7 +634,7 @@ contract GatewayTest is Test { vm.expectEmit(true, false, false, false); emit IGateway.OutboundMessageAccepted(assetHubParaID.into(), 1, messageID, bytes("")); - IGateway(address(gateway)).sendToken{value: 2 ether}(address(token), destPara, recipientAddress20, 1); + IGateway(address(gateway)).sendToken{value: totalFee}(address(token), destPara, recipientAddress20, 1); } function testSendTokenAddress20FailsInvalidDestination() public { From ac5c8b1b96ea7fddecc2a047de440ded423ed4fe Mon Sep 17 00:00:00 2001 From: Vincent Geddes Date: Wed, 22 Nov 2023 16:48:03 +0200 Subject: [PATCH 03/38] Improve fee query API --- contracts/src/Gateway.sol | 10 +++---- contracts/src/Types.sol | 12 ++++++++ contracts/src/interfaces/IGateway.sol | 6 ++-- contracts/test/Gateway.t.sol | 31 ++++++++++----------- contracts/test/mocks/GatewayUpgradeMock.sol | 10 +++---- 5 files changed, 39 insertions(+), 30 deletions(-) diff --git a/contracts/src/Gateway.sol b/contracts/src/Gateway.sol index 7e4821bdff..11ba271539 100644 --- a/contracts/src/Gateway.sol +++ b/contracts/src/Gateway.sol @@ -8,7 +8,7 @@ import {Verification} from "./Verification.sol"; import {Assets} from "./Assets.sol"; import {AgentExecutor} from "./AgentExecutor.sol"; import {Agent} from "./Agent.sol"; -import {Channel, ChannelID, InboundMessage, OperatingMode, ParaID, Command, MultiAddress} from "./Types.sol"; +import {Channel, ChannelID, InboundMessage, OperatingMode, ParaID, Command, MultiAddress, Fee} from "./Types.sol"; import {IGateway} from "./interfaces/IGateway.sol"; import {IInitializable} from "./interfaces/IInitializable.sol"; import {ERC1967} from "./utils/ERC1967.sol"; @@ -440,9 +440,9 @@ contract Gateway is IGateway, IInitializable { */ // Total fee for registering a token - function registerTokenFee() external view returns (uint256, uint256) { + function registerTokenFee() external view returns (Fee memory) { Channel storage channel = _ensureChannel(ASSET_HUB_PARA_ID.into()); - return (channel.outboundFee, Assets.registerTokenFee()); + return Fee({bridge: channel.outboundFee, xcm: Assets.registerTokenFee()}); } // Register a token on AssetHub @@ -453,9 +453,9 @@ contract Gateway is IGateway, IInitializable { } // Total fee for sending a token - function sendTokenFee(address, ParaID destinationChain) external view returns (uint256, uint256) { + function sendTokenFee(address, ParaID destinationChain) external view returns (Fee memory) { Channel storage channel = _ensureChannel(ASSET_HUB_PARA_ID.into()); - return (channel.outboundFee, Assets.sendTokenFee(ASSET_HUB_PARA_ID, destinationChain)); + return Fee({bridge: channel.outboundFee, xcm: Assets.sendTokenFee(ASSET_HUB_PARA_ID, destinationChain)}); } // Transfer ERC20 tokens to a Polkadot parachain diff --git a/contracts/src/Types.sol b/contracts/src/Types.sol index f826c7add4..447e39b55f 100644 --- a/contracts/src/Types.sol +++ b/contracts/src/Types.sol @@ -87,3 +87,15 @@ enum Command { } enum AgentExecuteCommand {TransferToken} + + +using {total} for Fee global; + +struct Fee { + uint256 bridge; + uint256 xcm; +} + +function total(Fee memory fee) pure returns (uint256) { + return fee.bridge + fee.xcm; +} diff --git a/contracts/src/interfaces/IGateway.sol b/contracts/src/interfaces/IGateway.sol index a4ba7a5499..3350d78a38 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.22; -import {OperatingMode, InboundMessage, ParaID, ChannelID, MultiAddress} from "../Types.sol"; +import {OperatingMode, InboundMessage, ParaID, ChannelID, MultiAddress, Fee} from "../Types.sol"; import {Verification} from "../Verification.sol"; interface IGateway { @@ -78,7 +78,7 @@ interface IGateway { /// @dev Fee schedule in Ether for registering a token, covering /// 1. Delivery costs to BridgeHub /// 2. XCM Execution costs on AssetHub - function registerTokenFee() external view returns (uint256, uint256); + function registerTokenFee() external view returns (Fee memory); /// @dev Send a message to the AssetHub parachain to register a new fungible asset /// in the `ForeignAssets` pallet. @@ -87,7 +87,7 @@ interface IGateway { /// @dev Fees in Ether for sending a token /// 1. Delivery costs to BridgeHub /// 2. XCM execution costs on destinationChain - function sendTokenFee(address token, ParaID destinationChain) external view returns (uint256, uint256); + function sendTokenFee(address token, ParaID destinationChain) external view returns (Fee memory); /// @dev Send ERC20 tokens to parachain `destinationChain` and deposit into account `destinationAddress` function sendToken(address token, ParaID destinationChain, MultiAddress calldata destinationAddress, uint128 amount) diff --git a/contracts/test/Gateway.t.sol b/contracts/test/Gateway.t.sol index de3a731253..361c3a06b8 100644 --- a/contracts/test/Gateway.t.sol +++ b/contracts/test/Gateway.t.sol @@ -10,6 +10,7 @@ import {BeefyClient} from "../src/BeefyClient.sol"; import {IGateway} from "../src/interfaces/IGateway.sol"; import {IInitializable} from "../src/interfaces/IInitializable.sol"; import {Gateway} from "../src/Gateway.sol"; +import {Fee} from "../src/Types.sol"; import {GatewayMock, GatewayV2} from "./mocks/GatewayMock.sol"; import {GatewayProxy} from "../src/GatewayProxy.sol"; @@ -276,15 +277,14 @@ contract GatewayTest is Test { address user = makeAddr("user"); deal(address(token), user, 1); - (uint256 bridgeFee, uint256 xcmFee) = IGateway(address(gateway)).sendTokenFee(address(token), ParaID.wrap(0)); - uint256 totalFee = bridgeFee + xcmFee; + Fee memory fee = IGateway(address(gateway)).sendTokenFee(address(token), ParaID.wrap(0)); // Let gateway lock up to 1 tokens hoax(user); token.approve(address(gateway), 1); - hoax(user, totalFee); - IGateway(address(gateway)).sendToken{value: totalFee}(address(token), ParaID.wrap(0), recipientAddress32, 1); + hoax(user, fee.total()); + IGateway(address(gateway)).sendToken{value: fee.total()}(address(token), ParaID.wrap(0), recipientAddress32, 1); assertEq(user.balance, 0); } @@ -584,8 +584,7 @@ contract GatewayTest is Test { // Multilocation for recipient ParaID destPara = ParaID.wrap(2043); - (uint256 bridgeFee, uint256 xcmFee) = IGateway(address(gateway)).sendTokenFee(address(token), destPara); - uint256 totalFee = bridgeFee + xcmFee; + Fee memory fee = IGateway(address(gateway)).sendTokenFee(address(token), destPara); vm.expectEmit(true, true, false, true); emit IGateway.TokenSent(address(this), address(token), destPara, recipientAddress32, 1); @@ -594,7 +593,7 @@ contract GatewayTest is Test { vm.expectEmit(true, false, false, false); emit IGateway.OutboundMessageAccepted(assetHubParaID.into(), 1, messageID, bytes("")); - IGateway(address(gateway)).sendToken{value: totalFee}(address(token), destPara, recipientAddress32, 1); + IGateway(address(gateway)).sendToken{value: fee.total()}(address(token), destPara, recipientAddress32, 1); } function testSendTokenAddress32ToAssetHub() public { @@ -604,8 +603,7 @@ contract GatewayTest is Test { // Multilocation for recipient ParaID destPara = assetHubParaID; - (uint256 bridgeFee, uint256 xcmFee) = IGateway(address(gateway)).sendTokenFee(address(token), destPara); - uint256 totalFee = bridgeFee + xcmFee; + Fee memory fee = IGateway(address(gateway)).sendTokenFee(address(token), destPara); vm.expectEmit(true, true, false, true); emit IGateway.TokenSent(address(this), address(token), destPara, recipientAddress32, 1); @@ -614,7 +612,7 @@ contract GatewayTest is Test { vm.expectEmit(true, false, false, false); emit IGateway.OutboundMessageAccepted(assetHubParaID.into(), 1, messageID, bytes("")); - IGateway(address(gateway)).sendToken{value: totalFee}(address(token), destPara, recipientAddress32, 1); + IGateway(address(gateway)).sendToken{value: fee.total()}(address(token), destPara, recipientAddress32, 1); } function testSendTokenAddress20() public { @@ -624,8 +622,7 @@ contract GatewayTest is Test { // Multilocation for recipient ParaID destPara = ParaID.wrap(2043); - (uint256 bridgeFee, uint256 xcmFee) = IGateway(address(gateway)).sendTokenFee(address(token), destPara); - uint256 totalFee = bridgeFee + xcmFee; + Fee memory fee = IGateway(address(gateway)).sendTokenFee(address(token), destPara); vm.expectEmit(true, true, false, true); emit IGateway.TokenSent(address(this), address(token), destPara, recipientAddress20, 1); @@ -634,7 +631,7 @@ contract GatewayTest is Test { vm.expectEmit(true, false, false, false); emit IGateway.OutboundMessageAccepted(assetHubParaID.into(), 1, messageID, bytes("")); - IGateway(address(gateway)).sendToken{value: totalFee}(address(token), destPara, recipientAddress20, 1); + IGateway(address(gateway)).sendToken{value: fee.total()}(address(token), destPara, recipientAddress20, 1); } function testSendTokenAddress20FailsInvalidDestination() public { @@ -772,13 +769,13 @@ contract GatewayTest is Test { } function testSetTokenFees() public { - (, uint256 fee) = IGateway(address(gateway)).registerTokenFee(); - assertEq(fee, 1 ether); + Fee memory fee = IGateway(address(gateway)).registerTokenFee(); + assertEq(fee.xcm, 1 ether); GatewayMock(address(gateway)).setTokenTransferFeesPublic( abi.encode(Gateway.SetTokenTransferFeesParams({register: 2, send: 1})) ); - (, fee) = IGateway(address(gateway)).registerTokenFee(); - assertEq(fee, 2); + fee = IGateway(address(gateway)).registerTokenFee(); + assertEq(fee.xcm, 2); } bytes32 public expectChannelIDBytes = bytes32(0xc173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539); diff --git a/contracts/test/mocks/GatewayUpgradeMock.sol b/contracts/test/mocks/GatewayUpgradeMock.sol index 1beefa2bf4..78ca002c02 100644 --- a/contracts/test/mocks/GatewayUpgradeMock.sol +++ b/contracts/test/mocks/GatewayUpgradeMock.sol @@ -2,7 +2,7 @@ // SPDX-FileCopyrightText: 2023 Snowfork pragma solidity 0.8.22; -import {Channel, InboundMessage, OperatingMode, ParaID, Command, ChannelID, MultiAddress} from "../../src/Types.sol"; +import {Channel, InboundMessage, OperatingMode, ParaID, Command, ChannelID, MultiAddress, Fee} from "../../src/Types.sol"; import {IGateway} from "../../src/interfaces/IGateway.sol"; import {IInitializable} from "../../src/interfaces/IInitializable.sol"; import {Verification} from "../../src/Verification.sol"; @@ -38,14 +38,14 @@ contract GatewayUpgradeMock is IGateway, IInitializable { function submitInbound(InboundMessage calldata, bytes32[] calldata, Verification.Proof calldata) external {} - function registerTokenFee() external pure returns (uint256, uint256) { - return (1, 1); + function registerTokenFee() external pure returns (Fee memory) { + return Fee(1, 1); } function registerToken(address) external payable {} - function sendTokenFee(address, ParaID) external pure returns (uint256, uint256) { - return (1, 1); + function sendTokenFee(address, ParaID) external pure returns (Fee memory) { + return Fee(1, 1); } function sendToken(address, ParaID, MultiAddress calldata, uint128) external payable {} From 0eb03f2be24d3878d4c68d2da5d8c8d9fdf5ce47 Mon Sep 17 00:00:00 2001 From: Vincent Geddes Date: Thu, 23 Nov 2023 11:42:41 +0200 Subject: [PATCH 04/38] Add destinationChainFee parameter --- contracts/src/interfaces/IGateway.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/src/interfaces/IGateway.sol b/contracts/src/interfaces/IGateway.sol index 3350d78a38..89997985ab 100644 --- a/contracts/src/interfaces/IGateway.sol +++ b/contracts/src/interfaces/IGateway.sol @@ -90,7 +90,7 @@ interface IGateway { function sendTokenFee(address token, ParaID destinationChain) external view returns (Fee memory); /// @dev Send ERC20 tokens to parachain `destinationChain` and deposit into account `destinationAddress` - function sendToken(address token, ParaID destinationChain, MultiAddress calldata destinationAddress, uint128 amount) + function sendToken(address token, ParaID destinationChain, MultiAddress calldata destinationAddress, uint256 destinationChainFee, uint128 amount) external payable; } From 26c909870411c1e20311b9cb67c1f762c4470b88 Mon Sep 17 00:00:00 2001 From: Vincent Geddes Date: Thu, 23 Nov 2023 11:43:21 +0200 Subject: [PATCH 05/38] forge install: prb-math v4.0.1 --- .gitmodules | 3 +++ contracts/lib/prb-math | 1 + 2 files changed, 4 insertions(+) create mode 160000 contracts/lib/prb-math diff --git a/.gitmodules b/.gitmodules index f6d32c8244..6b3399d887 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,3 +13,6 @@ [submodule "contracts/lib/canonical-weth"] path = contracts/lib/canonical-weth url = https://github.com/Snowfork/canonical-weth +[submodule "contracts/lib/prb-math"] + path = contracts/lib/prb-math + url = https://github.com/PaulRBerg/prb-math diff --git a/contracts/lib/prb-math b/contracts/lib/prb-math new file mode 160000 index 0000000000..77fa88eda4 --- /dev/null +++ b/contracts/lib/prb-math @@ -0,0 +1 @@ +Subproject commit 77fa88eda4a4a91b3f3e9431df291292c26b6c71 From 2fcc4159610b4ed7f718eca424a2cf25483c6de9 Mon Sep 17 00:00:00 2001 From: Vincent Geddes Date: Thu, 23 Nov 2023 21:10:18 +0200 Subject: [PATCH 06/38] Add exchage rate to gateway --- contracts/remappings.txt | 1 + contracts/src/Assets.sol | 31 ++++-- contracts/src/DeployScript.sol | 15 ++- contracts/src/Gateway.sol | 104 +++++++++++++----- contracts/src/SubstrateTypes.sol | 39 ++++--- contracts/src/Types.sol | 9 +- contracts/src/interfaces/IGateway.sol | 17 ++- contracts/src/storage/AssetsStorage.sol | 4 +- contracts/test/Gateway.t.sol | 102 ++++++++++++----- contracts/test/mocks/GatewayMock.sol | 21 +++- contracts/test/mocks/GatewayUpgradeMock.sol | 10 +- .../primitives/router/src/inbound/mod.rs | 19 +++- web/packages/test/scripts/set-env.sh | 4 + 13 files changed, 274 insertions(+), 102 deletions(-) diff --git a/contracts/remappings.txt b/contracts/remappings.txt index 865f4a3558..1777bcb267 100644 --- a/contracts/remappings.txt +++ b/contracts/remappings.txt @@ -3,3 +3,4 @@ ds-test/=lib/ds-test/src/ forge-std/=lib/forge-std/src/ openzeppelin-contracts/=lib/openzeppelin-contracts/ openzeppelin/=lib/openzeppelin-contracts/contracts/ +prb/math/=lib/prb-math/ diff --git a/contracts/src/Assets.sol b/contracts/src/Assets.sol index 16ff1e26e4..1ae1211455 100644 --- a/contracts/src/Assets.sol +++ b/contracts/src/Assets.sol @@ -24,7 +24,7 @@ library Assets { error Unsupported(); // This library requires state which must be initialized in the gateway's storage. - function initialize(uint256 _registerTokenFee, uint256 _sendTokenFee) external { + function initialize(uint128 _registerTokenFee, uint128 _sendTokenFee) external { AssetsStorage.Layout storage $ = AssetsStorage.layout(); $.registerTokenFee = _registerTokenFee; @@ -44,14 +44,18 @@ library Assets { IERC20(token).safeTransferFrom(sender, assetHubAgent, amount); } - function sendTokenFee(ParaID assetHubParaID, ParaID destinationChain) external view returns (uint256) { + function sendTokenFee(ParaID assetHubParaID, ParaID destinationChain, uint128 destinationChainFee) + external + view + returns (uint256) + { AssetsStorage.Layout storage $ = AssetsStorage.layout(); if (assetHubParaID == destinationChain) { return $.sendTokenFee; } // If the final destination chain is not AssetHub, then the fee needs to additionally // include the cost of executing an XCM on the final destination parachain. - return 2 * $.sendTokenFee; + return $.sendTokenFee + destinationChainFee; } function sendToken( @@ -61,6 +65,7 @@ library Assets { address sender, ParaID destinationChain, MultiAddress calldata destinationAddress, + uint128 destinationChainFee, uint128 amount ) external returns (bytes memory payload, uint256 extraFee) { AssetsStorage.Layout storage $ = AssetsStorage.layout(); @@ -69,7 +74,9 @@ library Assets { if (destinationChain == assetHubParaID) { if (destinationAddress.isAddress32()) { - payload = SubstrateTypes.SendTokenToAssetHubAddress32(token, destinationAddress.asAddress32(), amount); + payload = SubstrateTypes.SendTokenToAssetHubAddress32( + token, destinationAddress.asAddress32(), $.sendTokenFee, amount + ); } else { // AssetHub does not support 20-byte account IDs revert Unsupported(); @@ -78,18 +85,28 @@ library Assets { } else { if (destinationAddress.isAddress32()) { payload = SubstrateTypes.SendTokenToAddress32( - token, destinationChain, destinationAddress.asAddress32(), amount + token, + destinationChain, + destinationAddress.asAddress32(), + $.sendTokenFee, + destinationChainFee, + amount ); } else if (destinationAddress.isAddress20()) { payload = SubstrateTypes.SendTokenToAddress20( - token, destinationChain, destinationAddress.asAddress20(), amount + token, + destinationChain, + destinationAddress.asAddress20(), + $.sendTokenFee, + destinationChainFee, + amount ); } else { revert Unsupported(); } // If the final destination chain is not AssetHub, then the fee needs to additionally // include the cost of executing an XCM on the final destination parachain. - extraFee = 2 * $.sendTokenFee; + extraFee = $.sendTokenFee + destinationChainFee; } emit IGateway.TokenSent(sender, token, destinationChain, destinationAddress, amount); diff --git a/contracts/src/DeployScript.sol b/contracts/src/DeployScript.sol index 2f694d2e2b..e9447c4164 100644 --- a/contracts/src/DeployScript.sol +++ b/contracts/src/DeployScript.sol @@ -15,11 +15,14 @@ import {AgentExecutor} from "./AgentExecutor.sol"; import {ChannelID, ParaID, OperatingMode} from "./Types.sol"; import {SafeNativeTransfer} from "./utils/SafeTransfer.sol"; import {stdJson} from "forge-std/StdJson.sol"; +import {UD60x18, ud60x18, convert} from "prb/math/src/UD60x18.sol"; contract DeployScript is Script { using SafeNativeTransfer for address payable; using stdJson for string; + UD60x18 internal dotToEthDecimals; + function setUp() public {} function run() public { @@ -56,6 +59,8 @@ contract DeployScript is Script { ParaID assetHubParaID = ParaID.wrap(uint32(vm.envUint("ASSET_HUB_PARAID"))); bytes32 assetHubAgentID = vm.envBytes32("ASSET_HUB_AGENT_ID"); + dotToEthDecimals = convert(vm.envUint("DOT_TO_ETH_DECIMALS")); + AgentExecutor executor = new AgentExecutor(); Gateway gatewayLogic = new Gateway( address(beefyClient), @@ -63,7 +68,8 @@ contract DeployScript is Script { bridgeHubParaID, bridgeHubAgentID, assetHubParaID, - assetHubAgentID + assetHubAgentID, + dotToEthDecimals ); bool rejectOutboundMessages = vm.envBool("REJECT_OUTBOUND_MESSAGES"); @@ -76,9 +82,10 @@ contract DeployScript is Script { Gateway.Config memory config = Gateway.Config({ mode: defaultOperatingMode, - outboundFee: vm.envUint("DEFAULT_FEE"), - registerTokenFee: vm.envUint("REGISTER_NATIVE_TOKEN_FEE"), - sendTokenFee: vm.envUint("SEND_NATIVE_TOKEN_FEE") + fee: uint128(vm.envUint("DEFAULT_FEE")), + registerTokenFee: uint128(vm.envUint("REGISTER_NATIVE_TOKEN_FEE")), + sendTokenFee: uint128(vm.envUint("SEND_NATIVE_TOKEN_FEE")), + exchangeRate: ud60x18(0.0025e18) }); GatewayProxy gateway = new GatewayProxy(address(gatewayLogic), abi.encode(config)); diff --git a/contracts/src/Gateway.sol b/contracts/src/Gateway.sol index 11ba271539..049aef63d2 100644 --- a/contracts/src/Gateway.sol +++ b/contracts/src/Gateway.sol @@ -21,6 +21,8 @@ import {ScaleCodec} from "./utils/ScaleCodec.sol"; import {CoreStorage} from "./storage/CoreStorage.sol"; import {AssetsStorage} from "./storage/AssetsStorage.sol"; +import {UD60x18, ud60x18, convert} from "prb/math/src/UD60x18.sol"; + contract Gateway is IGateway, IInitializable { using Address for address; using SafeNativeTransfer for address payable; @@ -52,6 +54,8 @@ contract Gateway is IGateway, IInitializable { // 2. Calling implementation function uint256 DISPATCH_OVERHEAD_GAS = 10_000; + UD60x18 internal immutable DOT_TO_ETH_DECIMALS; + error InvalidProof(); error InvalidNonce(); error NotEnoughGas(); @@ -82,7 +86,8 @@ contract Gateway is IGateway, IInitializable { ParaID bridgeHubParaID, bytes32 bridgeHubAgentID, ParaID assetHubParaID, - bytes32 assetHubAgentID + bytes32 assetHubAgentID, + UD60x18 dotToEthDecimals ) { if ( bridgeHubParaID == ParaID.wrap(0) || bridgeHubAgentID == 0 || assetHubParaID == ParaID.wrap(0) @@ -98,12 +103,13 @@ contract Gateway is IGateway, IInitializable { BRIDGE_HUB_AGENT_ID = bridgeHubAgentID; ASSET_HUB_PARA_ID = assetHubParaID; ASSET_HUB_AGENT_ID = assetHubAgentID; + DOT_TO_ETH_DECIMALS = dotToEthDecimals; } /// @dev Submit a message from Polkadot for verification and dispatch /// @param message A message produced by the OutboundQueue pallet on BridgeHub /// @param leafProof A message proof used to verify that the message is in the merkle tree committed by the OutboundQueue pallet - /// @param headerProof A proof used to verify that the commitment was included in a BridgeHub header that was finalized by BEEFY. + /// @param headerProof A proof that the commitment is included in parachain header that was finalized by BEEFY. function submitInbound( InboundMessage calldata message, bytes32[] calldata leafProof, @@ -225,9 +231,9 @@ contract Gateway is IGateway, IInitializable { return (ch.inboundNonce, ch.outboundNonce); } - function channelOutboundFeeOf(ChannelID channelID) external view returns (uint256) { + function channelFeeOf(ChannelID channelID) external view returns (uint256) { Channel storage ch = _ensureChannel(channelID); - return ch.outboundFee; + return calculateLocalFee(ch.exchangeRate, ch.fee); } function agentOf(bytes32 agentID) external view returns (address) { @@ -317,7 +323,7 @@ contract Gateway is IGateway, IInitializable { ch.agent = agent; ch.inboundNonce = 0; ch.outboundNonce = 0; - ch.outboundFee = params.outboundFee; + ch.fee = params.outboundFee; emit ChannelCreated(params.channelID); } @@ -327,8 +333,11 @@ contract Gateway is IGateway, IInitializable { ChannelID channelID; /// @dev The new operating mode OperatingMode mode; - /// @dev The new fee for accepting outbound messages - uint256 outboundFee; + /// @dev The new fee in DOT for accepting outbound messages + uint128 fee; + /// @dev The new ETH/DOT exchange rate + uint128 exchangeRateNumerator; + uint128 exchangeRateDenominator; } /// @dev Update the configuration for a channel @@ -343,7 +352,8 @@ contract Gateway is IGateway, IInitializable { } ch.mode = params.mode; - ch.outboundFee = params.outboundFee; + ch.fee = params.fee; + ch.exchangeRate = convert(params.exchangeRateNumerator).div(convert(params.exchangeRateDenominator)); emit ChannelUpdated(params.channelID); } @@ -420,10 +430,10 @@ contract Gateway is IGateway, IInitializable { } struct SetTokenTransferFeesParams { - /// @dev The fee for register token - uint256 register; - /// @dev The fee for send token from ethereum to polkadot - uint256 send; + /// @dev The remote fee (DOT) for registering a token on AssetHub + uint128 register; + /// @dev The remote fee (DOT) for send tokens to AssetHub + uint128 send; } // @dev Set the operating mode of the gateway @@ -442,7 +452,10 @@ contract Gateway is IGateway, IInitializable { // Total fee for registering a token function registerTokenFee() external view returns (Fee memory) { Channel storage channel = _ensureChannel(ASSET_HUB_PARA_ID.into()); - return Fee({bridge: channel.outboundFee, xcm: Assets.registerTokenFee()}); + return Fee({ + bridge: calculateLocalFee(channel.exchangeRate, channel.fee), + xcm: calculateLocalFee(channel.exchangeRate, Assets.registerTokenFee()) + }); } // Register a token on AssetHub @@ -453,21 +466,40 @@ contract Gateway is IGateway, IInitializable { } // Total fee for sending a token - function sendTokenFee(address, ParaID destinationChain) external view returns (Fee memory) { + function sendTokenFee(address, ParaID destinationChain, uint128 destinationFee) + external + view + returns (Fee memory) + { Channel storage channel = _ensureChannel(ASSET_HUB_PARA_ID.into()); - return Fee({bridge: channel.outboundFee, xcm: Assets.sendTokenFee(ASSET_HUB_PARA_ID, destinationChain)}); + return Fee({ + bridge: calculateLocalFee(channel.exchangeRate, channel.fee), + xcm: calculateLocalFee( + channel.exchangeRate, Assets.sendTokenFee(ASSET_HUB_PARA_ID, destinationChain, destinationFee) + ) + }); } // Transfer ERC20 tokens to a Polkadot parachain - function sendToken(address token, ParaID destinationChain, MultiAddress calldata destinationAddress, uint128 amount) - external - payable - { + function sendToken( + address token, + ParaID destinationChain, + MultiAddress calldata destinationAddress, + uint128 destinationFee, + uint128 amount + ) external payable { CoreStorage.Layout storage $ = CoreStorage.layout(); address assetHubAgent = $.agents[ASSET_HUB_AGENT_ID]; (bytes memory payload, uint256 extraFee) = Assets.sendToken( - ASSET_HUB_PARA_ID, assetHubAgent, token, msg.sender, destinationChain, destinationAddress, amount + ASSET_HUB_PARA_ID, + assetHubAgent, + token, + msg.sender, + destinationChain, + destinationAddress, + destinationFee, + amount ); _submitOutbound(ASSET_HUB_PARA_ID, payload, extraFee); @@ -485,6 +517,13 @@ contract Gateway is IGateway, IInitializable { return Verification.verifyCommitment(BEEFY_CLIENT, BRIDGE_HUB_PARA_ID_ENCODED, commitment, proof); } + function calculateLocalFee(UD60x18 exchangeRate, uint256 remoteFee) internal pure returns (uint256) { + UD60x18 remoteFeeFP = convert(remoteFee); + UD60x18 localFeeFP = remoteFeeFP.mul(exchangeRate).mul(convert(1e8)); + uint256 localFee = convert(localFeeFP); + return localFee; + } + // Submit an outbound message to Polkadot function _submitOutbound(ParaID dest, bytes memory payload, uint256 extraFee) internal { ChannelID channelID = dest.into(); @@ -493,7 +532,7 @@ contract Gateway is IGateway, IInitializable { // Ensure outbound messaging is allowed _ensureOutboundMessagingEnabled(channel); - uint256 totalFee = channel.outboundFee + extraFee; + uint256 totalFee = calculateLocalFee(channel.exchangeRate, channel.fee + extraFee); // Ensure the user has enough funds for this message to be accepted if (msg.value < totalFee) { @@ -565,12 +604,14 @@ contract Gateway is IGateway, IInitializable { // Initial configuration for bridge struct Config { OperatingMode mode; - /// @dev The fee charged to users for submitting outbound messages. - uint256 outboundFee; - /// @dev The extra fee charged for registering tokens. - uint256 registerTokenFee; - /// @dev The extra fee charged for sending tokens. - uint256 sendTokenFee; + /// @dev The fee charged to users for submitting outbound messages (DOT) + uint128 fee; + /// @dev The extra fee charged for registering tokens (DOT) + uint128 registerTokenFee; + /// @dev The extra fee charged for sending tokens (DOT) + uint128 sendTokenFee; + /// @dev The ETH/DOT exchange rate + UD60x18 exchangeRate; } /// @dev Initialize storage in the gateway @@ -597,7 +638,8 @@ contract Gateway is IGateway, IInitializable { agent: bridgeHubAgent, inboundNonce: 0, outboundNonce: 0, - outboundFee: config.outboundFee + fee: config.fee, + exchangeRate: config.exchangeRate }); // Initialize channel for secondary governance track @@ -606,7 +648,8 @@ contract Gateway is IGateway, IInitializable { agent: bridgeHubAgent, inboundNonce: 0, outboundNonce: 0, - outboundFee: config.outboundFee + fee: config.fee, + exchangeRate: config.exchangeRate }); // Initialize agent for for AssetHub @@ -619,7 +662,8 @@ contract Gateway is IGateway, IInitializable { agent: assetHubAgent, inboundNonce: 0, outboundNonce: 0, - outboundFee: config.outboundFee + fee: config.fee, + exchangeRate: config.exchangeRate }); Assets.initialize(config.registerTokenFee, config.sendTokenFee); diff --git a/contracts/src/SubstrateTypes.sol b/contracts/src/SubstrateTypes.sol index fa6d6a2382..bbdd1f5870 100644 --- a/contracts/src/SubstrateTypes.sol +++ b/contracts/src/SubstrateTypes.sol @@ -67,7 +67,7 @@ library SubstrateTypes { * `NativeTokensMessage::Mint` */ // destination is AccountID32 address on AssetHub - function SendTokenToAssetHubAddress32(address token, bytes32 recipient, uint128 amount) + function SendTokenToAssetHubAddress32(address token, bytes32 recipient, uint128 xcmFee, uint128 amount) internal view returns (bytes memory) @@ -79,16 +79,20 @@ library SubstrateTypes { SubstrateTypes.H160(token), bytes1(0x00), recipient, - ScaleCodec.encodeU128(amount) + ScaleCodec.encodeU128(amount), + ScaleCodec.encodeU128(xcmFee) ); } // destination is AccountID32 address - function SendTokenToAddress32(address token, ParaID paraID, bytes32 recipient, uint128 amount) - internal - view - returns (bytes memory) - { + function SendTokenToAddress32( + address token, + ParaID paraID, + bytes32 recipient, + uint128 xcmFee, + uint128 destinationXcmFee, + uint128 amount + ) internal view returns (bytes memory) { return bytes.concat( bytes1(0x00), ScaleCodec.encodeU64(uint64(block.chainid)), @@ -97,16 +101,21 @@ library SubstrateTypes { bytes1(0x01), ScaleCodec.encodeU32(uint32(ParaID.unwrap(paraID))), recipient, - ScaleCodec.encodeU128(amount) + ScaleCodec.encodeU128(destinationXcmFee), + ScaleCodec.encodeU128(amount), + ScaleCodec.encodeU128(xcmFee) ); } // destination is AccountID20 address - function SendTokenToAddress20(address token, ParaID paraID, bytes20 recipient, uint128 amount) - internal - view - returns (bytes memory) - { + function SendTokenToAddress20( + address token, + ParaID paraID, + bytes20 recipient, + uint128 xcmFee, + uint128 destinationXcmFee, + uint128 amount + ) internal view returns (bytes memory) { return bytes.concat( bytes1(0x00), ScaleCodec.encodeU64(uint64(block.chainid)), @@ -115,7 +124,9 @@ library SubstrateTypes { bytes1(0x02), ScaleCodec.encodeU32(uint32(ParaID.unwrap(paraID))), recipient, - ScaleCodec.encodeU128(amount) + ScaleCodec.encodeU128(destinationXcmFee), + ScaleCodec.encodeU128(amount), + ScaleCodec.encodeU128(xcmFee) ); } } diff --git a/contracts/src/Types.sol b/contracts/src/Types.sol index 447e39b55f..729c1ea64f 100644 --- a/contracts/src/Types.sol +++ b/contracts/src/Types.sol @@ -6,6 +6,8 @@ import { MultiAddress, multiAddressFromUint32, multiAddressFromBytes32, multiAddressFromBytes20 } from "./MultiAddress.sol"; +import {UD60x18} from "prb/math/src/UD60x18.sol"; + type ParaID is uint32; using {ParaIDEq as ==, ParaIDNe as !=, into} for ParaID global; @@ -45,8 +47,10 @@ struct Channel { uint64 outboundNonce; /// @dev The address of the agent of the parachain owning this channel address agent; - /// @dev The fee charged to users for submitting outbound messages - uint256 outboundFee; + /// @dev The DOT fee charged to users for submitting outbound messages + uint256 fee; + /// @dev The ETH/DOT exchange rate + UD60x18 exchangeRate; } /// @dev Inbound message from a Polkadot parachain (via BridgeHub) @@ -88,7 +92,6 @@ enum Command { enum AgentExecuteCommand {TransferToken} - using {total} for Fee global; struct Fee { diff --git a/contracts/src/interfaces/IGateway.sol b/contracts/src/interfaces/IGateway.sol index 89997985ab..04e5e0fad0 100644 --- a/contracts/src/interfaces/IGateway.sol +++ b/contracts/src/interfaces/IGateway.sol @@ -40,7 +40,7 @@ interface IGateway { function operatingMode() external view returns (OperatingMode); function channelOperatingModeOf(ChannelID channelID) external view returns (OperatingMode); - function channelOutboundFeeOf(ChannelID channelID) external view returns (uint256); + function channelFeeOf(ChannelID channelID) external view returns (uint256); function channelNoncesOf(ChannelID channelID) external view returns (uint64, uint64); function agentOf(bytes32 agentID) external view returns (address); function implementation() external view returns (address); @@ -87,10 +87,17 @@ interface IGateway { /// @dev Fees in Ether for sending a token /// 1. Delivery costs to BridgeHub /// 2. XCM execution costs on destinationChain - function sendTokenFee(address token, ParaID destinationChain) external view returns (Fee memory); + function sendTokenFee(address token, ParaID destinationChain, uint128 destinationFee) + external + view + returns (Fee memory); /// @dev Send ERC20 tokens to parachain `destinationChain` and deposit into account `destinationAddress` - function sendToken(address token, ParaID destinationChain, MultiAddress calldata destinationAddress, uint256 destinationChainFee, uint128 amount) - external - payable; + function sendToken( + address token, + ParaID destinationChain, + MultiAddress calldata destinationAddress, + uint128 destinationFee, + uint128 amount + ) external payable; } diff --git a/contracts/src/storage/AssetsStorage.sol b/contracts/src/storage/AssetsStorage.sol index 110e20f9b1..4b926441c7 100644 --- a/contracts/src/storage/AssetsStorage.sol +++ b/contracts/src/storage/AssetsStorage.sol @@ -4,8 +4,8 @@ pragma solidity 0.8.22; library AssetsStorage { struct Layout { - uint256 registerTokenFee; - uint256 sendTokenFee; + uint128 registerTokenFee; + uint128 sendTokenFee; } bytes32 internal constant SLOT = keccak256("org.snowbridge.storage.assets"); diff --git a/contracts/test/Gateway.t.sol b/contracts/test/Gateway.t.sol index 361c3a06b8..592beef98d 100644 --- a/contracts/test/Gateway.t.sol +++ b/contracts/test/Gateway.t.sol @@ -35,6 +35,7 @@ import { import {WETH9} from "canonical-weth/WETH9.sol"; import "./mocks/GatewayUpgradeMock.sol"; +import {UD60x18, ud60x18, convert} from "prb/math/src/UD60x18.sol"; contract GatewayTest is Test { ParaID public bridgeHubParaID = ParaID.wrap(1001); @@ -63,13 +64,22 @@ contract GatewayTest is Test { uint256 public reward = 1 ether; bytes32 public messageID = keccak256("cabbage"); - uint256 public outboundFee = 1 ether; - uint256 public registerNativeTokenFee = 1 ether; - uint256 public sendNativeTokenFee = 1 ether; + // remote fees in DOT + uint128 public outboundFee = 1e10; + uint128 public registerTokenFee = 1e10; + uint128 public sendTokenFee = 1e10; MultiAddress public recipientAddress32; MultiAddress public recipientAddress20; + // DOT amounts need to be multiplied by 10^(18 - 10) to have the same number + // decimal places as ETH (18 decimal places) + // UD60x18.convert(1e8) == ud60x18(1e26) + UD60x18 public dotToEthDecimals = ud60x18(1e26); + + // ETH/DOT exchange rate + UD60x18 public exchangeRate = ud60x18(0.0025e18); + function setUp() public { AgentExecutor executor = new AgentExecutor(); gatewayLogic = new GatewayMock( @@ -78,15 +88,17 @@ contract GatewayTest is Test { bridgeHubParaID, bridgeHubAgentID, assetHubParaID, - assetHubAgentID + assetHubAgentID, + dotToEthDecimals ); gateway = new GatewayProxy( address(gatewayLogic), abi.encode( OperatingMode.Normal, outboundFee, - registerNativeTokenFee, - sendNativeTokenFee + registerTokenFee, + sendTokenFee, + exchangeRate ) ); GatewayMock(address(gateway)).setCommitmentsAreVerified(true); @@ -277,14 +289,16 @@ contract GatewayTest is Test { address user = makeAddr("user"); deal(address(token), user, 1); - Fee memory fee = IGateway(address(gateway)).sendTokenFee(address(token), ParaID.wrap(0)); + Fee memory fee = IGateway(address(gateway)).sendTokenFee(address(token), ParaID.wrap(0), 1); // Let gateway lock up to 1 tokens hoax(user); token.approve(address(gateway), 1); hoax(user, fee.total()); - IGateway(address(gateway)).sendToken{value: fee.total()}(address(token), ParaID.wrap(0), recipientAddress32, 1); + IGateway(address(gateway)).sendToken{value: fee.total()}( + address(token), ParaID.wrap(0), recipientAddress32, 1, 1 + ); assertEq(user.balance, 0); } @@ -301,7 +315,9 @@ contract GatewayTest is Test { vm.expectRevert(Gateway.FeePaymentToLow.selector); hoax(user, 2 ether); - IGateway(address(gateway)).sendToken{value: 0.5 ether}(address(token), ParaID.wrap(0), recipientAddress32, 1); + IGateway(address(gateway)).sendToken{value: 0.002 ether}( + address(token), ParaID.wrap(0), recipientAddress32, 1, 1 + ); assertEq(user.balance, 2 ether); } @@ -412,11 +428,16 @@ contract GatewayTest is Test { } function testUpdateChannel() public { + // get current fee (0.0025 ether) + uint256 fee = IGateway(address(gateway)).channelFeeOf(assetHubParaID.into()); + bytes memory params = abi.encode( Gateway.UpdateChannelParams({ channelID: assetHubParaID.into(), mode: OperatingMode.RejectingOutboundMessages, - outboundFee: 2 ether + fee: outboundFee * 1, + exchangeRateNumerator: 1, + exchangeRateDenominator: 800 }) ); @@ -424,8 +445,9 @@ contract GatewayTest is Test { emit IGateway.ChannelUpdated(assetHubParaID.into()); GatewayMock(address(gateway)).updateChannelPublic(params); - uint256 fee = IGateway(address(gateway)).channelOutboundFeeOf(assetHubParaID.into()); - assertEq(fee, 2 ether); + // Due to the new exchange rate, new fee is halved + uint256 newFee = IGateway(address(gateway)).channelFeeOf(assetHubParaID.into()); + assertEq(fee / 2, newFee); } function testUpdateChannelFailDoesNotExist() public { @@ -433,7 +455,9 @@ contract GatewayTest is Test { Gateway.UpdateChannelParams({ channelID: ParaID.wrap(5956).into(), mode: OperatingMode.RejectingOutboundMessages, - outboundFee: 2 ether + fee: outboundFee * 2, + exchangeRateNumerator: 1, + exchangeRateDenominator: 800 }) ); @@ -446,7 +470,9 @@ contract GatewayTest is Test { Gateway.UpdateChannelParams({ channelID: ChannelID.wrap(bytes32(uint256(1))), mode: OperatingMode.RejectingOutboundMessages, - outboundFee: 1 ether + fee: outboundFee * 2, + exchangeRateNumerator: 1, + exchangeRateDenominator: 800 }) ); @@ -566,7 +592,9 @@ contract GatewayTest is Test { vm.expectEmit(true, false, false, false); emit IGateway.OutboundMessageAccepted(assetHubParaID.into(), 1, messageID, bytes("")); - uint256 totalFee = outboundFee + registerNativeTokenFee; + uint256 totalFee = + GatewayMock(address(gateway)).calculateLocalFeePublic(exchangeRate, outboundFee + registerTokenFee); + uint256 balanceBefore = address(this).balance; IGateway(address(gateway)).registerToken{value: totalFee + 1 ether}(address(token)); uint256 balanceAfter = address(this).balance; @@ -584,7 +612,7 @@ contract GatewayTest is Test { // Multilocation for recipient ParaID destPara = ParaID.wrap(2043); - Fee memory fee = IGateway(address(gateway)).sendTokenFee(address(token), destPara); + Fee memory fee = IGateway(address(gateway)).sendTokenFee(address(token), destPara, 1); vm.expectEmit(true, true, false, true); emit IGateway.TokenSent(address(this), address(token), destPara, recipientAddress32, 1); @@ -593,7 +621,7 @@ contract GatewayTest is Test { vm.expectEmit(true, false, false, false); emit IGateway.OutboundMessageAccepted(assetHubParaID.into(), 1, messageID, bytes("")); - IGateway(address(gateway)).sendToken{value: fee.total()}(address(token), destPara, recipientAddress32, 1); + IGateway(address(gateway)).sendToken{value: fee.total()}(address(token), destPara, recipientAddress32, 1, 1); } function testSendTokenAddress32ToAssetHub() public { @@ -603,7 +631,7 @@ contract GatewayTest is Test { // Multilocation for recipient ParaID destPara = assetHubParaID; - Fee memory fee = IGateway(address(gateway)).sendTokenFee(address(token), destPara); + Fee memory fee = IGateway(address(gateway)).sendTokenFee(address(token), destPara, 1); vm.expectEmit(true, true, false, true); emit IGateway.TokenSent(address(this), address(token), destPara, recipientAddress32, 1); @@ -612,7 +640,7 @@ contract GatewayTest is Test { vm.expectEmit(true, false, false, false); emit IGateway.OutboundMessageAccepted(assetHubParaID.into(), 1, messageID, bytes("")); - IGateway(address(gateway)).sendToken{value: fee.total()}(address(token), destPara, recipientAddress32, 1); + IGateway(address(gateway)).sendToken{value: fee.total()}(address(token), destPara, recipientAddress32, 1, 1); } function testSendTokenAddress20() public { @@ -622,7 +650,7 @@ contract GatewayTest is Test { // Multilocation for recipient ParaID destPara = ParaID.wrap(2043); - Fee memory fee = IGateway(address(gateway)).sendTokenFee(address(token), destPara); + Fee memory fee = IGateway(address(gateway)).sendTokenFee(address(token), destPara, 1); vm.expectEmit(true, true, false, true); emit IGateway.TokenSent(address(this), address(token), destPara, recipientAddress20, 1); @@ -631,7 +659,7 @@ contract GatewayTest is Test { vm.expectEmit(true, false, false, false); emit IGateway.OutboundMessageAccepted(assetHubParaID.into(), 1, messageID, bytes("")); - IGateway(address(gateway)).sendToken{value: fee.total()}(address(token), destPara, recipientAddress20, 1); + IGateway(address(gateway)).sendToken{value: fee.total()}(address(token), destPara, recipientAddress20, 1, 1); } function testSendTokenAddress20FailsInvalidDestination() public { @@ -642,7 +670,7 @@ contract GatewayTest is Test { // Should fail to send tokens to AssetHub vm.expectRevert(Assets.Unsupported.selector); - IGateway(address(gateway)).sendToken{value: 2 ether}(address(token), destPara, recipientAddress20, 1); + IGateway(address(gateway)).sendToken{value: 2 ether}(address(token), destPara, recipientAddress20, 1, 1); } /** @@ -673,7 +701,9 @@ contract GatewayTest is Test { Gateway.UpdateChannelParams({ channelID: assetHubParaID.into(), mode: OperatingMode.RejectingOutboundMessages, - outboundFee: 1 ether + fee: outboundFee * 2, + exchangeRateNumerator: 1, + exchangeRateDenominator: 800 }) ); GatewayMock(address(gateway)).updateChannelPublic(params); @@ -687,7 +717,7 @@ contract GatewayTest is Test { IGateway(address(gateway)).registerToken{value: 1 ether}(address(token)); vm.expectRevert(Gateway.Disabled.selector); - IGateway(address(gateway)).sendToken{value: 1 ether}(address(token), ParaID.wrap(0), recipientAddress32, 1); + IGateway(address(gateway)).sendToken{value: 1 ether}(address(token), ParaID.wrap(0), recipientAddress32, 1, 1); } /** @@ -736,8 +766,8 @@ contract GatewayTest is Test { OperatingMode channelMode = gw.channelOperatingModeOf(assetHubParaID.into()); assertEq(uint256(channelMode), 0); - (uint256 fee) = gw.channelOutboundFeeOf(assetHubParaID.into()); - assertEq(fee, 1 ether); + uint256 fee = gw.channelFeeOf(assetHubParaID.into()); + assertEq(fee, 0.0025 ether); (uint64 inbound, uint64 outbound) = gw.channelNoncesOf(assetHubParaID.into()); assertEq(inbound, 0); @@ -768,14 +798,28 @@ contract GatewayTest is Test { ); } + function testCalculateLocalFee() public { + // 400 DOT = 1 ETH + uint256 remoteFee = 400e10; + uint256 localFee = GatewayMock(address(gateway)).calculateLocalFeePublic(exchangeRate, remoteFee); + assertEq(localFee, 1 ether); + + // 1 DOT = 0.0025 ETH + remoteFee = 1e10; + localFee = GatewayMock(address(gateway)).calculateLocalFeePublic(exchangeRate, remoteFee); + assertEq(localFee, 0.0025 ether); + } + function testSetTokenFees() public { + // Double the fees + Fee memory fee = IGateway(address(gateway)).registerTokenFee(); - assertEq(fee.xcm, 1 ether); + assertEq(fee.xcm, 0.0025 ether); GatewayMock(address(gateway)).setTokenTransferFeesPublic( - abi.encode(Gateway.SetTokenTransferFeesParams({register: 2, send: 1})) + abi.encode(Gateway.SetTokenTransferFeesParams({register: registerTokenFee * 2, send: sendTokenFee * 2})) ); fee = IGateway(address(gateway)).registerTokenFee(); - assertEq(fee.xcm, 2); + assertEq(fee.xcm, 0.005e18); } bytes32 public expectChannelIDBytes = bytes32(0xc173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539); diff --git a/contracts/test/mocks/GatewayMock.sol b/contracts/test/mocks/GatewayMock.sol index 9ddb5f5d0a..287769b5a3 100644 --- a/contracts/test/mocks/GatewayMock.sol +++ b/contracts/test/mocks/GatewayMock.sol @@ -6,6 +6,8 @@ import {ParaID, OperatingMode} from "../../src/Types.sol"; import {CoreStorage} from "../../src/storage/CoreStorage.sol"; import {Verification} from "../../src/Verification.sol"; +import {UD60x18} from "prb/math/src/UD60x18.sol"; + contract GatewayMock is Gateway { bool public commitmentsAreVerified; @@ -15,8 +17,19 @@ contract GatewayMock is Gateway { ParaID bridgeHubParaID, bytes32 bridgeHubHubAgentID, ParaID assetHubParaID, - bytes32 assetHubHubAgentID - ) Gateway(beefyClient, agentExecutor, bridgeHubParaID, bridgeHubHubAgentID, assetHubParaID, assetHubHubAgentID) {} + bytes32 assetHubHubAgentID, + UD60x18 dotToEthDecimals + ) + Gateway( + beefyClient, + agentExecutor, + bridgeHubParaID, + bridgeHubHubAgentID, + assetHubParaID, + assetHubHubAgentID, + dotToEthDecimals + ) + {} function agentExecutePublic(bytes calldata params) external { this.agentExecute(params); @@ -67,6 +80,10 @@ contract GatewayMock is Gateway { function setTokenTransferFeesPublic(bytes calldata params) external { this.setTokenTransferFees(params); } + + function calculateLocalFeePublic(UD60x18 exchangeRate, uint256 remoteFee) external pure returns (uint256) { + return calculateLocalFee(exchangeRate, remoteFee); + } } library AdditionalStorage { diff --git a/contracts/test/mocks/GatewayUpgradeMock.sol b/contracts/test/mocks/GatewayUpgradeMock.sol index 78ca002c02..00ccb3427c 100644 --- a/contracts/test/mocks/GatewayUpgradeMock.sol +++ b/contracts/test/mocks/GatewayUpgradeMock.sol @@ -2,7 +2,9 @@ // SPDX-FileCopyrightText: 2023 Snowfork pragma solidity 0.8.22; -import {Channel, InboundMessage, OperatingMode, ParaID, Command, ChannelID, MultiAddress, Fee} from "../../src/Types.sol"; +import { + Channel, InboundMessage, OperatingMode, ParaID, Command, ChannelID, MultiAddress, Fee +} from "../../src/Types.sol"; import {IGateway} from "../../src/interfaces/IGateway.sol"; import {IInitializable} from "../../src/interfaces/IInitializable.sol"; import {Verification} from "../../src/Verification.sol"; @@ -20,7 +22,7 @@ contract GatewayUpgradeMock is IGateway, IInitializable { return OperatingMode.Normal; } - function channelOutboundFeeOf(ChannelID) external pure returns (uint256) { + function channelFeeOf(ChannelID) external pure returns (uint256) { return 0; } @@ -44,11 +46,11 @@ contract GatewayUpgradeMock is IGateway, IInitializable { function registerToken(address) external payable {} - function sendTokenFee(address, ParaID) external pure returns (Fee memory) { + function sendTokenFee(address, ParaID, uint128) external pure returns (Fee memory) { return Fee(1, 1); } - function sendToken(address, ParaID, MultiAddress calldata, uint128) external payable {} + function sendToken(address, ParaID, MultiAddress calldata, uint128, uint128) external payable {} event Initialized(uint256 d0, uint256 d1); diff --git a/parachain/primitives/router/src/inbound/mod.rs b/parachain/primitives/router/src/inbound/mod.rs index 1d42a445f6..f222823a62 100644 --- a/parachain/primitives/router/src/inbound/mod.rs +++ b/parachain/primitives/router/src/inbound/mod.rs @@ -46,6 +46,9 @@ pub enum Command { RegisterToken { /// The address of the ERC20 token to be bridged over to AssetHub token: H160, + /// The fee for executing the XCM on AssetHub + /// Includes the XCM fee and the registration deposit + fee: u128, }, /// Send a token to AssetHub or another parachain SendToken { @@ -55,6 +58,8 @@ pub enum Command { destination: Destination, /// Amount to transfer amount: u128, + /// XCM execution fee on AssetHub + fee: u128, }, } @@ -66,11 +71,21 @@ pub enum Destination { /// The funds will deposited into the sovereign account of destination parachain `para_id` on /// AssetHub, Account `id` on the destination parachain will receive the funds via a /// reserve-backed transfer. See https://github.com/paritytech/xcm-format#depositreserveasset - ForeignAccountId32 { para_id: u32, id: [u8; 32] }, + ForeignAccountId32 { + para_id: u32, + id: [u8; 32], + /// XCM execution fee on final destination + fee: u128, + }, /// The funds will deposited into the sovereign account of destination parachain `para_id` on /// AssetHub, Account `id` on the destination parachain will receive the funds via a /// reserve-backed transfer. See https://github.com/paritytech/xcm-format#depositreserveasset - ForeignAccountId20 { para_id: u32, id: [u8; 20] }, + ForeignAccountId20 { + para_id: u32, + id: [u8; 20], + /// XCM execution fee on final destination + fee: u128, + }, } pub struct MessageToXcm< diff --git a/web/packages/test/scripts/set-env.sh b/web/packages/test/scripts/set-env.sh index b6c80bfe35..a204c02a97 100755 --- a/web/packages/test/scripts/set-env.sh +++ b/web/packages/test/scripts/set-env.sh @@ -50,6 +50,10 @@ export TEMPLATE_CHANNEL_ID="0x26c13363ad6499b895574b3ca482545dda41d657ffc5673b39 export PRIMARY_GOVERNANCE_CHANNEL_ID="0x0000000000000000000000000000000000000000000000000000000000000001" export SECONDARY_GOVERNANCE_CHANNEL_ID="0x0000000000000000000000000000000000000000000000000000000000000002" +# ROC and KSM amounts need to be multiplied by 10^(18 - 12) to have the same number +# of decimal places as ETH (18 decimal places) +export DOT_TO_ETH_DECIMALS=1000000 + relaychain_ws_url="${RELAYCHAIN_WS_URL:-ws://127.0.0.1:9944}" relaychain_sudo_seed="${RELAYCHAIN_SUDO_SEED:-//Alice}" From d88dfd5779e331c4b3da7cb6d1e358e91a1da5a6 Mon Sep 17 00:00:00 2001 From: Vincent Geddes Date: Sun, 26 Nov 2023 14:05:37 +0200 Subject: [PATCH 07/38] Update gateway --- contracts/src/Assets.sol | 68 +++++---- contracts/src/DeployScript.sol | 2 +- contracts/src/Gateway.sol | 137 ++++++++--------- contracts/src/Types.sol | 14 +- contracts/src/interfaces/IGateway.sol | 7 +- contracts/src/storage/AssetsStorage.sol | 9 +- contracts/src/storage/PricingStorage.sol | 23 +++ contracts/test/mocks/GatewayUpgradeMock.sol | 12 +- parachain/pallets/control/src/lib.rs | 143 +++++++++++++----- parachain/pallets/control/src/mock.rs | 15 +- parachain/pallets/control/src/tests.rs | 40 +++-- parachain/pallets/inbound-queue/src/lib.rs | 17 ++- parachain/pallets/inbound-queue/src/test.rs | 36 +++-- parachain/pallets/outbound-queue/src/lib.rs | 108 ++++++------- parachain/pallets/outbound-queue/src/mock.rs | 17 ++- .../outbound-queue/src/send_message_impl.rs | 3 +- parachain/pallets/outbound-queue/src/test.rs | 47 ------ parachain/pallets/outbound-queue/src/types.rs | 8 +- parachain/primitives/core/src/lib.rs | 29 +++- parachain/primitives/core/src/outbound.rs | 42 +++-- parachain/primitives/core/src/pricing.rs | 67 ++++++++ .../primitives/router/src/inbound/mod.rs | 84 ++++------ 22 files changed, 552 insertions(+), 376 deletions(-) create mode 100644 contracts/src/storage/PricingStorage.sol create mode 100644 parachain/primitives/core/src/pricing.rs diff --git a/contracts/src/Assets.sol b/contracts/src/Assets.sol index 1ae1211455..bc89c362e8 100644 --- a/contracts/src/Assets.sol +++ b/contracts/src/Assets.sol @@ -9,7 +9,7 @@ import {SafeTokenTransferFrom} from "./utils/SafeTransfer.sol"; import {AssetsStorage} from "./storage/AssetsStorage.sol"; import {SubstrateTypes} from "./SubstrateTypes.sol"; -import {ParaID, MultiAddress} from "./Types.sol"; +import {ParaID, MultiAddress, Ticket, Cost} from "./Types.sol"; import {Address} from "./utils/Address.sol"; /// @title Library for implementing Ethereum->Polkadot ERC20 transfers. @@ -23,14 +23,6 @@ library Assets { error InvalidDestination(); error Unsupported(); - // This library requires state which must be initialized in the gateway's storage. - function initialize(uint128 _registerTokenFee, uint128 _sendTokenFee) external { - AssetsStorage.Layout storage $ = AssetsStorage.layout(); - - $.registerTokenFee = _registerTokenFee; - $.sendTokenFee = _sendTokenFee; - } - /// @dev transfer tokens from the sender to the specified function _transferToAgent(address assetHubAgent, address token, address sender, uint128 amount) internal { if (!token.isContract()) { @@ -44,18 +36,28 @@ library Assets { IERC20(token).safeTransferFrom(sender, assetHubAgent, amount); } - function sendTokenFee(ParaID assetHubParaID, ParaID destinationChain, uint128 destinationChainFee) + function sendTokenCosts(ParaID assetHubParaID, ParaID destinationChain, uint128 destinationChainFee) external view - returns (uint256) + returns (Cost memory costs) + { + return _sendTokenCosts(assetHubParaID, destinationChain, destinationChainFee); + } + + function _sendTokenCosts(ParaID assetHubParaID, ParaID destinationChain, uint128 destinationChainFee) + internal + view + returns (Cost memory cost) { AssetsStorage.Layout storage $ = AssetsStorage.layout(); if (assetHubParaID == destinationChain) { - return $.sendTokenFee; + cost.remote = $.assetHubReserveTransferFee; + } else { + // If the final destination chain is not AssetHub, then the fee needs to additionally + // include the cost of executing an XCM on the final destination parachain. + cost.remote = $.assetHubReserveTransferFee + destinationChainFee; } - // If the final destination chain is not AssetHub, then the fee needs to additionally - // include the cost of executing an XCM on the final destination parachain. - return $.sendTokenFee + destinationChainFee; + cost.local = 0; } function sendToken( @@ -67,67 +69,69 @@ library Assets { MultiAddress calldata destinationAddress, uint128 destinationChainFee, uint128 amount - ) external returns (bytes memory payload, uint256 extraFee) { + ) external returns (Ticket memory ticket) { AssetsStorage.Layout storage $ = AssetsStorage.layout(); _transferToAgent(assetHubAgent, token, sender, amount); + ticket.cost = _sendTokenCosts(assetHubParaID, destinationChain, destinationChainFee); if (destinationChain == assetHubParaID) { if (destinationAddress.isAddress32()) { - payload = SubstrateTypes.SendTokenToAssetHubAddress32( - token, destinationAddress.asAddress32(), $.sendTokenFee, amount + ticket.payload = SubstrateTypes.SendTokenToAssetHubAddress32( + token, destinationAddress.asAddress32(), $.assetHubReserveTransferFee, amount ); } else { // AssetHub does not support 20-byte account IDs revert Unsupported(); } - extraFee = $.sendTokenFee; } else { if (destinationAddress.isAddress32()) { - payload = SubstrateTypes.SendTokenToAddress32( + ticket.payload = SubstrateTypes.SendTokenToAddress32( token, destinationChain, destinationAddress.asAddress32(), - $.sendTokenFee, + $.assetHubReserveTransferFee, destinationChainFee, amount ); } else if (destinationAddress.isAddress20()) { - payload = SubstrateTypes.SendTokenToAddress20( + ticket.payload = SubstrateTypes.SendTokenToAddress20( token, destinationChain, destinationAddress.asAddress20(), - $.sendTokenFee, + $.assetHubReserveTransferFee, destinationChainFee, amount ); } else { revert Unsupported(); } - // If the final destination chain is not AssetHub, then the fee needs to additionally - // include the cost of executing an XCM on the final destination parachain. - extraFee = $.sendTokenFee + destinationChainFee; } - emit IGateway.TokenSent(sender, token, destinationChain, destinationAddress, amount); } - function registerTokenFee() external view returns (uint256) { + + function registerTokenCosts() external view returns (Cost memory costs) { + return _registerTokenCosts(); + } + + function _registerTokenCosts() internal view returns (Cost memory costs) { AssetsStorage.Layout storage $ = AssetsStorage.layout(); - return $.registerTokenFee; + costs.remote = $.assetHubCreateAssetFee; + costs.local = $.registerTokenFee; } /// @dev Enqueues a create native token message to substrate. /// @param token The ERC20 token address. - function registerToken(address token) external returns (bytes memory payload, uint256 extraFee) { + function registerToken(address token) external returns (Ticket memory ticket) { AssetsStorage.Layout storage $ = AssetsStorage.layout(); if (!token.isContract()) { revert InvalidToken(); } - payload = SubstrateTypes.RegisterToken(token); - extraFee = $.registerTokenFee; + ticket.cost = _registerTokenCosts(); + ticket.payload = SubstrateTypes.RegisterToken(token); emit IGateway.TokenRegistrationSent(token); } diff --git a/contracts/src/DeployScript.sol b/contracts/src/DeployScript.sol index e9447c4164..92443dfcdc 100644 --- a/contracts/src/DeployScript.sol +++ b/contracts/src/DeployScript.sol @@ -82,7 +82,7 @@ contract DeployScript is Script { Gateway.Config memory config = Gateway.Config({ mode: defaultOperatingMode, - fee: uint128(vm.envUint("DEFAULT_FEE")), + deliveryCost: uint128(vm.envUint("DEFAULT_FEE")), registerTokenFee: uint128(vm.envUint("REGISTER_NATIVE_TOKEN_FEE")), sendTokenFee: uint128(vm.envUint("SEND_NATIVE_TOKEN_FEE")), exchangeRate: ud60x18(0.0025e18) diff --git a/contracts/src/Gateway.sol b/contracts/src/Gateway.sol index 049aef63d2..6de385fcdc 100644 --- a/contracts/src/Gateway.sol +++ b/contracts/src/Gateway.sol @@ -8,7 +8,7 @@ import {Verification} from "./Verification.sol"; import {Assets} from "./Assets.sol"; import {AgentExecutor} from "./AgentExecutor.sol"; import {Agent} from "./Agent.sol"; -import {Channel, ChannelID, InboundMessage, OperatingMode, ParaID, Command, MultiAddress, Fee} from "./Types.sol"; +import {Channel, ChannelID, InboundMessage, OperatingMode, ParaID, Command, MultiAddress, Ticket, Cost} from "./Types.sol"; import {IGateway} from "./interfaces/IGateway.sol"; import {IInitializable} from "./interfaces/IInitializable.sol"; import {ERC1967} from "./utils/ERC1967.sol"; @@ -19,6 +19,7 @@ import {Math} from "./utils/Math.sol"; import {ScaleCodec} from "./utils/ScaleCodec.sol"; import {CoreStorage} from "./storage/CoreStorage.sol"; +import {PricingStorage} from "./storage/PricingStorage.sol"; import {AssetsStorage} from "./storage/AssetsStorage.sol"; import {UD60x18, ud60x18, convert} from "prb/math/src/UD60x18.sol"; @@ -231,11 +232,6 @@ contract Gateway is IGateway, IInitializable { return (ch.inboundNonce, ch.outboundNonce); } - function channelFeeOf(ChannelID channelID) external view returns (uint256) { - Channel storage ch = _ensureChannel(channelID); - return calculateLocalFee(ch.exchangeRate, ch.fee); - } - function agentOf(bytes32 agentID) external view returns (address) { return _ensureAgent(agentID); } @@ -300,8 +296,6 @@ contract Gateway is IGateway, IInitializable { bytes32 agentID; /// @dev Initial operating mode OperatingMode mode; - /// @dev outbound fee - uint256 outboundFee; } /// @dev Create a messaging channel for a Polkadot parachain @@ -323,7 +317,6 @@ contract Gateway is IGateway, IInitializable { ch.agent = agent; ch.inboundNonce = 0; ch.outboundNonce = 0; - ch.fee = params.outboundFee; emit ChannelCreated(params.channelID); } @@ -352,9 +345,6 @@ contract Gateway is IGateway, IInitializable { } ch.mode = params.mode; - ch.fee = params.fee; - ch.exchangeRate = convert(params.exchangeRateNumerator).div(convert(params.exchangeRateDenominator)); - emit ChannelUpdated(params.channelID); } @@ -431,18 +421,21 @@ contract Gateway is IGateway, IInitializable { struct SetTokenTransferFeesParams { /// @dev The remote fee (DOT) for registering a token on AssetHub - uint128 register; + uint128 assetHubCreateAssetFee; /// @dev The remote fee (DOT) for send tokens to AssetHub - uint128 send; + uint128 assetHubReserveTransferFee; + /// @dev extra fee to register an asset and discourage spamming + uint128 registerTokenFee; } // @dev Set the operating mode of the gateway function setTokenTransferFees(bytes calldata data) external onlySelf { AssetsStorage.Layout storage $ = AssetsStorage.layout(); SetTokenTransferFeesParams memory params = abi.decode(data, (SetTokenTransferFeesParams)); - $.registerTokenFee = params.register; - $.sendTokenFee = params.send; - emit TokenTransferFeesChanged(params.register, params.send); + $.assetHubCreateAssetFee = params.assetHubCreateAssetFee; + $.assetHubReserveTransferFee = params.assetHubReserveTransferFee; + $.registerTokenFee = params.registerTokenFee; + emit TokenTransferFeesChanged(); } /** @@ -450,34 +443,26 @@ contract Gateway is IGateway, IInitializable { */ // Total fee for registering a token - function registerTokenFee() external view returns (Fee memory) { - Channel storage channel = _ensureChannel(ASSET_HUB_PARA_ID.into()); - return Fee({ - bridge: calculateLocalFee(channel.exchangeRate, channel.fee), - xcm: calculateLocalFee(channel.exchangeRate, Assets.registerTokenFee()) - }); + function registerTokenFee() external view returns (uint256) { + Cost memory cost = Assets.registerTokenCosts(); + return _calculateFee(cost); } // Register a token on AssetHub function registerToken(address token) external payable { - (bytes memory payload, uint256 extraFee) = Assets.registerToken(token); + (bytes memory payload, uint128 extraCosts) = Assets.registerToken(token); - _submitOutbound(ASSET_HUB_PARA_ID, payload, extraFee); + _submitOutbound(ASSET_HUB_PARA_ID, payload, extraCosts); } // Total fee for sending a token function sendTokenFee(address, ParaID destinationChain, uint128 destinationFee) external view - returns (Fee memory) + returns (uint256) { - Channel storage channel = _ensureChannel(ASSET_HUB_PARA_ID.into()); - return Fee({ - bridge: calculateLocalFee(channel.exchangeRate, channel.fee), - xcm: calculateLocalFee( - channel.exchangeRate, Assets.sendTokenFee(ASSET_HUB_PARA_ID, destinationChain, destinationFee) - ) - }); + Cost memory cost = Assets.sendTokenFee(ASSET_HUB_PARA_ID, destinationChain, destinationFee); + return _calculateFee(cost); } // Transfer ERC20 tokens to a Polkadot parachain @@ -491,7 +476,7 @@ contract Gateway is IGateway, IInitializable { CoreStorage.Layout storage $ = CoreStorage.layout(); address assetHubAgent = $.agents[ASSET_HUB_AGENT_ID]; - (bytes memory payload, uint256 extraFee) = Assets.sendToken( + Ticket memory ticket = Assets.sendToken( ASSET_HUB_PARA_ID, assetHubAgent, token, @@ -502,7 +487,7 @@ contract Gateway is IGateway, IInitializable { amount ); - _submitOutbound(ASSET_HUB_PARA_ID, payload, extraFee); + _submitOutbound(ASSET_HUB_PARA_ID, ticket); } /* Internal functions */ @@ -517,42 +502,50 @@ contract Gateway is IGateway, IInitializable { return Verification.verifyCommitment(BEEFY_CLIENT, BRIDGE_HUB_PARA_ID_ENCODED, commitment, proof); } - function calculateLocalFee(UD60x18 exchangeRate, uint256 remoteFee) internal pure returns (uint256) { - UD60x18 remoteFeeFP = convert(remoteFee); - UD60x18 localFeeFP = remoteFeeFP.mul(exchangeRate).mul(convert(1e8)); - uint256 localFee = convert(localFeeFP); - return localFee; + // Convert ROC/KSM/DOT to ETH + function _convertToNative(UD60x18 exchangeRate, uint128 amount) internal pure returns (uint256) { + UD60x18 amountFP = convert(amount); + UD60x18 nativeAmountFP = amountFP.mul(exchangeRate).mul(convert(DOT_TO_ETH_DECIMALS)); + uint256 nativeAmount = convert(nativeAmountFP); + return nativeAmount; + } + + // Calculate the fee for accepting an outbound message + function _calculateFee(Cost memory cost) internal view returns (uint256) { + PricingStorage.Layout storage pricing = PricingStorage.layout(); + return _convertToNative(pricing.exchangeRate, pricing.deliveryCost + cost.remote) + cost.local; } // Submit an outbound message to Polkadot - function _submitOutbound(ParaID dest, bytes memory payload, uint256 extraFee) internal { + function _submitOutbound(ParaID dest, Ticket memory ticket) internal { ChannelID channelID = dest.into(); Channel storage channel = _ensureChannel(channelID); + PricingStorage.Layout storage pricing = PricingStorage.layout(); // Ensure outbound messaging is allowed _ensureOutboundMessagingEnabled(channel); - uint256 totalFee = calculateLocalFee(channel.exchangeRate, channel.fee + extraFee); + uint256 fee = _calculateFee(ticket.cost); // Ensure the user has enough funds for this message to be accepted - if (msg.value < totalFee) { + if (msg.value < fee) { revert FeePaymentToLow(); } channel.outboundNonce = channel.outboundNonce + 1; // Deposit total fee into agent's contract - payable(channel.agent).safeNativeTransfer(totalFee); + payable(channel.agent).safeNativeTransfer(fee); // Reimburse excess fee payment - if (msg.value > totalFee) { - payable(msg.sender).safeNativeTransfer(msg.value - totalFee); + if (msg.value > fee) { + payable(msg.sender).safeNativeTransfer(msg.value - fee); } // Generate a unique ID for this message bytes32 messageID = keccak256(abi.encodePacked(channelID, channel.outboundNonce)); - emit IGateway.OutboundMessageAccepted(channelID, channel.outboundNonce, messageID, payload); + emit IGateway.OutboundMessageAccepted(channelID, channel.outboundNonce, messageID, ticket.payload); } /// @dev Outbound message can be disabled globally or on a per-channel basis. @@ -605,13 +598,15 @@ contract Gateway is IGateway, IInitializable { struct Config { OperatingMode mode; /// @dev The fee charged to users for submitting outbound messages (DOT) - uint128 fee; - /// @dev The extra fee charged for registering tokens (DOT) - uint128 registerTokenFee; - /// @dev The extra fee charged for sending tokens (DOT) - uint128 sendTokenFee; + uint128 deliveryCost; /// @dev The ETH/DOT exchange rate UD60x18 exchangeRate; + /// @dev The extra fee charged for registering tokens (DOT) + uint128 assetHubCreateAssetFee; + /// @dev The extra fee charged for sending tokens (DOT) + uint128 assetHubReserveTransferFee; + /// @dev extra fee to discourage spamming + uint256 registerTokenFee; } /// @dev Initialize storage in the gateway @@ -624,48 +619,50 @@ contract Gateway is IGateway, IInitializable { Config memory config = abi.decode(data, (Config)); - CoreStorage.Layout storage $ = CoreStorage.layout(); - - $.mode = config.mode; + CoreStorage.Layout storage core = CoreStorage.layout(); + core.mode = config.mode; // Initialize agent for BridgeHub address bridgeHubAgent = address(new Agent(BRIDGE_HUB_AGENT_ID)); - $.agents[BRIDGE_HUB_AGENT_ID] = bridgeHubAgent; + core.agents[BRIDGE_HUB_AGENT_ID] = bridgeHubAgent; // Initialize channel for primary governance track - $.channels[PRIMARY_GOVERNANCE_CHANNEL_ID] = Channel({ + core.channels[PRIMARY_GOVERNANCE_CHANNEL_ID] = Channel({ mode: OperatingMode.Normal, agent: bridgeHubAgent, inboundNonce: 0, - outboundNonce: 0, - fee: config.fee, - exchangeRate: config.exchangeRate + outboundNonce: 0 }); // Initialize channel for secondary governance track - $.channels[SECONDARY_GOVERNANCE_CHANNEL_ID] = Channel({ + core.channels[SECONDARY_GOVERNANCE_CHANNEL_ID] = Channel({ mode: OperatingMode.Normal, agent: bridgeHubAgent, inboundNonce: 0, - outboundNonce: 0, - fee: config.fee, - exchangeRate: config.exchangeRate + outboundNonce: 0 }); // Initialize agent for for AssetHub address assetHubAgent = address(new Agent(ASSET_HUB_AGENT_ID)); - $.agents[ASSET_HUB_AGENT_ID] = assetHubAgent; + core.agents[ASSET_HUB_AGENT_ID] = assetHubAgent; // Initialize channel for AssetHub - $.channels[ASSET_HUB_PARA_ID.into()] = Channel({ + core.channels[ASSET_HUB_PARA_ID.into()] = Channel({ mode: OperatingMode.Normal, agent: assetHubAgent, inboundNonce: 0, - outboundNonce: 0, - fee: config.fee, - exchangeRate: config.exchangeRate + outboundNonce: 0 }); - Assets.initialize(config.registerTokenFee, config.sendTokenFee); + // Initialize pricing storage + PricingStorage.Layout storage pricing = PricingStorage.layout(); + pricing.exchangeRate = config.exchangeRate; + pricing.deliveryCost = config.deliveryCost; + + // Initialize assets storage + AssetsStorage.Layout storage assets = AssetsStorage.layout(); + assets.registerTokenFee = config.registerTokenFee; + assets.assetHubAssetCreationFee = config.assetHubAssetCreationFee; + assets.assetHubReserveTransferFee = config.assetHubReserveTransferFee; } } diff --git a/contracts/src/Types.sol b/contracts/src/Types.sol index 729c1ea64f..bb32639ed5 100644 --- a/contracts/src/Types.sol +++ b/contracts/src/Types.sol @@ -47,10 +47,6 @@ struct Channel { uint64 outboundNonce; /// @dev The address of the agent of the parachain owning this channel address agent; - /// @dev The DOT fee charged to users for submitting outbound messages - uint256 fee; - /// @dev The ETH/DOT exchange rate - UD60x18 exchangeRate; } /// @dev Inbound message from a Polkadot parachain (via BridgeHub) @@ -102,3 +98,13 @@ struct Fee { function total(Fee memory fee) pure returns (uint256) { return fee.bridge + fee.xcm; } + +struct Cost { + uint256 remote; + uint256 local; +} + +struct Ticket { + Cost cost; + bytes payload; +} diff --git a/contracts/src/interfaces/IGateway.sol b/contracts/src/interfaces/IGateway.sol index 04e5e0fad0..34fb590793 100644 --- a/contracts/src/interfaces/IGateway.sol +++ b/contracts/src/interfaces/IGateway.sol @@ -40,7 +40,6 @@ interface IGateway { function operatingMode() external view returns (OperatingMode); function channelOperatingModeOf(ChannelID channelID) external view returns (OperatingMode); - function channelFeeOf(ChannelID channelID) external view returns (uint256); function channelNoncesOf(ChannelID channelID) external view returns (uint64, uint64); function agentOf(bytes32 agentID) external view returns (address); function implementation() external view returns (address); @@ -61,7 +60,7 @@ interface IGateway { */ // @dev Emitted when the fees updated - event TokenTransferFeesChanged(uint256 register, uint256 send); + event TokenTransferFeesChanged(); /// @dev Emitted once the funds are locked and an outbound message is successfully queued. event TokenSent( @@ -78,7 +77,7 @@ interface IGateway { /// @dev Fee schedule in Ether for registering a token, covering /// 1. Delivery costs to BridgeHub /// 2. XCM Execution costs on AssetHub - function registerTokenFee() external view returns (Fee memory); + function registerTokenFee() external view returns (uint256); /// @dev Send a message to the AssetHub parachain to register a new fungible asset /// in the `ForeignAssets` pallet. @@ -90,7 +89,7 @@ interface IGateway { function sendTokenFee(address token, ParaID destinationChain, uint128 destinationFee) external view - returns (Fee memory); + returns (uint256); /// @dev Send ERC20 tokens to parachain `destinationChain` and deposit into account `destinationAddress` function sendToken( diff --git a/contracts/src/storage/AssetsStorage.sol b/contracts/src/storage/AssetsStorage.sol index 4b926441c7..dbea7484b2 100644 --- a/contracts/src/storage/AssetsStorage.sol +++ b/contracts/src/storage/AssetsStorage.sol @@ -4,8 +4,13 @@ pragma solidity 0.8.22; library AssetsStorage { struct Layout { - uint128 registerTokenFee; - uint128 sendTokenFee; + // XCM fee charged by AssetHub for registering a token (DOT) + uint128 assetHubCreateAssetFee; + // XCM fee charged by AssetHub for receiving a token from the Gateway (DOT) + uint128 assetHubReserveTransferFee; + // Extra fee for registering a token, to discourage spamming (Ether) + uint256 registerTokenFee; + } bytes32 internal constant SLOT = keccak256("org.snowbridge.storage.assets"); diff --git a/contracts/src/storage/PricingStorage.sol b/contracts/src/storage/PricingStorage.sol new file mode 100644 index 0000000000..44e62001e4 --- /dev/null +++ b/contracts/src/storage/PricingStorage.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023 Snowfork +pragma solidity 0.8.22; + +import {UD60x18} from "prb/math/src/UD60x18.sol"; + +library PricingStorage { + struct Layout { + /// @dev The ETH/DOT exchange rate + UD60x18 exchangeRate; + /// @dev The cost of delivering messages to BridgeHub in DOT + uint128 deliveryCost; + } + + bytes32 internal constant SLOT = keccak256("org.snowbridge.storage.pricing"); + + function layout() internal pure returns (Layout storage $) { + bytes32 slot = SLOT; + assembly { + $.slot := slot + } + } +} diff --git a/contracts/test/mocks/GatewayUpgradeMock.sol b/contracts/test/mocks/GatewayUpgradeMock.sol index 00ccb3427c..3c77886f1f 100644 --- a/contracts/test/mocks/GatewayUpgradeMock.sol +++ b/contracts/test/mocks/GatewayUpgradeMock.sol @@ -22,10 +22,6 @@ contract GatewayUpgradeMock is IGateway, IInitializable { return OperatingMode.Normal; } - function channelFeeOf(ChannelID) external pure returns (uint256) { - return 0; - } - function channelNoncesOf(ChannelID) external pure returns (uint64, uint64) { return (0, 0); } @@ -40,14 +36,14 @@ contract GatewayUpgradeMock is IGateway, IInitializable { function submitInbound(InboundMessage calldata, bytes32[] calldata, Verification.Proof calldata) external {} - function registerTokenFee() external pure returns (Fee memory) { - return Fee(1, 1); + function registerTokenFee() external pure returns (uint256) { + return 1; } function registerToken(address) external payable {} - function sendTokenFee(address, ParaID, uint128) external pure returns (Fee memory) { - return Fee(1, 1); + function sendTokenFee(address, ParaID, uint128) external pure returns (uint256) { + return 1; } function sendToken(address, ParaID, MultiAddress calldata, uint128, uint128) external payable {} diff --git a/parachain/pallets/control/src/lib.rs b/parachain/pallets/control/src/lib.rs index 0209a14b6f..7a82c6e90d 100644 --- a/parachain/pallets/control/src/lib.rs +++ b/parachain/pallets/control/src/lib.rs @@ -52,33 +52,36 @@ pub mod api; pub mod weights; pub use weights::*; -use frame_support::traits::fungible::{Inspect, Mutate}; -use sp_core::{RuntimeDebug, H160, H256}; -use sp_io::hashing::blake2_256; -use sp_runtime::{traits::BadOrigin, DispatchError}; -use sp_std::prelude::*; -use xcm::prelude::*; -use xcm_executor::traits::ConvertLocation; - use frame_support::{ pallet_prelude::*, - traits::{tokens::Preservation, EnsureOrigin}, + traits::{ + fungible::Mutate, + tokens::{Balance, Preservation}, + EnsureOrigin, + }, }; use frame_system::pallet_prelude::*; use snowbridge_core::{ outbound::{Command, Initializer, Message, OperatingMode, SendError, SendMessage}, - sibling_sovereign_account, AgentId, Channel, ChannelId, ChannelLookup, ParaId, - BRIDGE_HUB_AGENT_ID, PRIMARY_GOVERNANCE_CHANNEL, SECONDARY_GOVERNANCE_CHANNEL, + sibling_sovereign_account, AgentId, Channel, ChannelId, ParaId, + PricingParameters as PricingParametersRecord, BRIDGE_HUB_AGENT_ID, PRIMARY_GOVERNANCE_CHANNEL, + SECONDARY_GOVERNANCE_CHANNEL, }; +use sp_core::{RuntimeDebug, H160, H256}; +use sp_io::hashing::blake2_256; +use sp_runtime::{traits::BadOrigin, DispatchError}; +use sp_std::prelude::*; +use xcm::prelude::*; +use xcm_executor::traits::ConvertLocation; #[cfg(feature = "runtime-benchmarks")] use frame_support::traits::OriginTrait; pub use pallet::*; -pub type BalanceOf = - <::Token as Inspect<::AccountId>>::Balance; +pub type BalanceOf = ::Balance; pub type AccountIdOf = ::AccountId; +pub type PricingParametersOf = PricingParametersRecord>; /// Ensure origin location is a sibling fn ensure_sibling(location: &MultiLocation) -> Result<(ParaId, H256), DispatchError> @@ -123,6 +126,8 @@ where #[frame_support::pallet] pub mod pallet { + use snowbridge_core::StaticLookup; + use super::*; #[pallet::pallet] @@ -141,6 +146,8 @@ pub mod pallet { /// Converts MultiLocation to AgentId type AgentIdOf: ConvertLocation; + type Balance: Balance + Into; + /// Token reserved for control operations type Token: Mutate; @@ -148,6 +155,12 @@ pub mod pallet { #[pallet::constant] type TreasuryAccount: Get; + /// Number of decimal places of local currency + type DefaultPricingParameters: Get>; + + /// Cost of delivering a message from Ethereum + type InboundDeliveryCost: Get>; + type WeightInfo: WeightInfo; #[cfg(feature = "runtime-benchmarks")] @@ -158,19 +171,45 @@ pub mod pallet { #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { /// An Upgrade message was sent to the Gateway - Upgrade { impl_address: H160, impl_code_hash: H256, initializer_params_hash: Option }, + Upgrade { + impl_address: H160, + impl_code_hash: H256, + initializer_params_hash: Option, + }, /// An CreateAgent message was sent to the Gateway - CreateAgent { location: Box, agent_id: AgentId }, + CreateAgent { + location: Box, + agent_id: AgentId, + }, /// An CreateChannel message was sent to the Gateway - CreateChannel { channel_id: ChannelId, agent_id: AgentId }, + CreateChannel { + channel_id: ChannelId, + agent_id: AgentId, + }, /// An UpdateChannel message was sent to the Gateway - UpdateChannel { channel_id: ChannelId, mode: OperatingMode, outbound_fee: u128 }, + UpdateChannel { + channel_id: ChannelId, + mode: OperatingMode, + outbound_fee: u128, + }, /// An SetOperatingMode message was sent to the Gateway - SetOperatingMode { mode: OperatingMode }, + SetOperatingMode { + mode: OperatingMode, + }, /// An TransferNativeFromAgent message was sent to the Gateway - TransferNativeFromAgent { agent_id: AgentId, recipient: H160, amount: u128 }, + TransferNativeFromAgent { + agent_id: AgentId, + recipient: H160, + amount: u128, + }, /// A SetTokenTransferFees message was sent to the Gateway - SetTokenTransferFees { register: u128, send: u128 }, + SetTokenTransferFees { + register: u128, + send: u128, + }, + PricingParametersChanged { + params: PricingParametersOf, + }, } #[pallet::error] @@ -184,6 +223,7 @@ pub mod pallet { InvalidLocation, Send(SendError), InvalidTokenTransferFees, + InvalidPricingParameters, } /// The set of registered agents @@ -196,6 +236,11 @@ pub mod pallet { #[pallet::getter(fn channels)] pub type Channels = StorageMap<_, Twox64Concat, ChannelId, Channel, OptionQuery>; + #[pallet::storage] + #[pallet::getter(fn parameters)] + pub type PricingParameters = + StorageValue<_, PricingParametersOf, ValueQuery, T::DefaultPricingParameters>; + #[pallet::genesis_config] #[derive(frame_support::DefaultNoBound)] pub struct GenesisConfig { @@ -290,13 +335,33 @@ pub mod pallet { Ok(()) } + #[pallet::call_index(2)] + #[pallet::weight((T::DbWeight::get().reads_writes(1, 1), DispatchClass::Operational))] + pub fn set_pricing_parameters( + origin: OriginFor, + params: PricingParametersOf, + ) -> DispatchResult { + ensure_root(origin)?; + params.validate().map_err(|_| Error::::InvalidPricingParameters)?; + PricingParameters::::put(params.clone()); + + let command = Command::SetPricingParameters { + exchange_rate: params.exchange_rate.into(), + delivery_cost: T::InboundDeliveryCost::get().into(), + }; + Self::send(PRIMARY_GOVERNANCE_CHANNEL, command, PaysFee::::No)?; + + Self::deposit_event(Event::PricingParametersChanged { params }); + Ok(()) + } + /// Sends a command to the Gateway contract to instantiate a new agent contract representing /// `origin`. /// /// Fee required: Yes /// /// - `origin`: Must be `MultiLocation` of a sibling parachain - #[pallet::call_index(2)] + #[pallet::call_index(3)] #[pallet::weight(T::WeightInfo::create_agent())] pub fn create_agent(origin: OriginFor) -> DispatchResult { let origin_location: MultiLocation = T::SiblingOrigin::ensure_origin(origin)?; @@ -331,13 +396,9 @@ pub mod pallet { /// - `origin`: Must be `MultiLocation` /// - `mode`: Initial operating mode of the channel /// - `outbound_fee`: Fee charged to users for sending outbound messages to Polkadot - #[pallet::call_index(3)] + #[pallet::call_index(4)] #[pallet::weight(T::WeightInfo::create_channel())] - pub fn create_channel( - origin: OriginFor, - mode: OperatingMode, - outbound_fee: u128, - ) -> DispatchResult { + pub fn create_channel(origin: OriginFor, mode: OperatingMode) -> DispatchResult { let origin_location: MultiLocation = T::SiblingOrigin::ensure_origin(origin)?; // Ensure that origin location is a sibling parachain @@ -351,7 +412,7 @@ pub mod pallet { let channel = Channel { agent_id, para_id }; Channels::::insert(channel_id, channel); - let command = Command::CreateChannel { channel_id, agent_id, mode, outbound_fee }; + let command = Command::CreateChannel { channel_id, agent_id, mode }; let pays_fee = PaysFee::::Yes(sibling_sovereign_account::(para_id)); Self::send(SECONDARY_GOVERNANCE_CHANNEL, command, pays_fee)?; @@ -368,7 +429,7 @@ pub mod pallet { /// - `origin`: Must be `MultiLocation` /// - `mode`: Initial operating mode of the channel /// - `outbound_fee`: Fee charged to users for sending outbound messages to Polkadot - #[pallet::call_index(4)] + #[pallet::call_index(5)] #[pallet::weight(T::WeightInfo::update_channel())] pub fn update_channel( origin: OriginFor, @@ -384,7 +445,7 @@ pub mod pallet { ensure!(Channels::::contains_key(channel_id), Error::::NoChannel); - let command = Command::UpdateChannel { channel_id, mode, outbound_fee }; + let command = Command::UpdateChannel { channel_id, mode }; let pays_fee = PaysFee::::Partial(sibling_sovereign_account::(para_id)); // Parachains send the update message on their own channel @@ -404,7 +465,7 @@ pub mod pallet { /// - `channel_id`: ID of channel /// - `mode`: Initial operating mode of the channel /// - `outbound_fee`: Fee charged to users for sending outbound messages to Polkadot - #[pallet::call_index(5)] + #[pallet::call_index(6)] #[pallet::weight(T::WeightInfo::force_update_channel())] pub fn force_update_channel( origin: OriginFor, @@ -416,7 +477,7 @@ pub mod pallet { ensure!(Channels::::contains_key(channel_id), Error::::NoChannel); - let command = Command::UpdateChannel { channel_id, mode, outbound_fee }; + let command = Command::UpdateChannel { channel_id, mode }; Self::send(SECONDARY_GOVERNANCE_CHANNEL, command, PaysFee::::No)?; Self::deposit_event(Event::::UpdateChannel { channel_id, mode, outbound_fee }); @@ -428,7 +489,7 @@ pub mod pallet { /// Fee required: No /// /// - `origin`: Must be `MultiLocation` - #[pallet::call_index(6)] + #[pallet::call_index(7)] #[pallet::weight(T::WeightInfo::transfer_native_from_agent())] pub fn transfer_native_from_agent( origin: OriginFor, @@ -461,7 +522,7 @@ pub mod pallet { /// - `location`: Location used to resolve the agent /// - `recipient`: Recipient of funds /// - `amount`: Amount to transfer - #[pallet::call_index(7)] + #[pallet::call_index(8)] #[pallet::weight(T::WeightInfo::force_transfer_native_from_agent())] pub fn force_transfer_native_from_agent( origin: OriginFor, @@ -497,7 +558,7 @@ pub mod pallet { /// - `origin`: Must be root /// - `register`: The fee for register token /// - `send`: The fee for send token to parachain - #[pallet::call_index(8)] + #[pallet::call_index(9)] #[pallet::weight(T::WeightInfo::set_token_transfer_fees())] pub fn set_token_transfer_fees( origin: OriginFor, @@ -565,9 +626,17 @@ pub mod pallet { } } - impl ChannelLookup for Pallet { - fn lookup(channel_id: ChannelId) -> Option { + impl StaticLookup for Pallet { + type Source = ChannelId; + type Target = Channel; + fn lookup(channel_id: Self::Source) -> Option { Channels::::get(channel_id) } } + + impl Get> for Pallet { + fn get() -> PricingParametersOf { + PricingParameters::::get() + } + } } diff --git a/parachain/pallets/control/src/mock.rs b/parachain/pallets/control/src/mock.rs index df8dbcfaae..5668bde7cd 100644 --- a/parachain/pallets/control/src/mock.rs +++ b/parachain/pallets/control/src/mock.rs @@ -11,11 +11,12 @@ use sp_core::H256; use xcm_executor::traits::ConvertLocation; use snowbridge_core::{ - outbound::ConstantGasMeter, sibling_sovereign_account, AgentId, AllowSiblingsOnly, ParaId, + gwei, meth, outbound::ConstantGasMeter, sibling_sovereign_account, AgentId, AllowSiblingsOnly, + ParaId, PricingParameters, Rewards, }; use sp_runtime::{ traits::{AccountIdConversion, BlakeTwo256, IdentityLookup, Keccak256}, - AccountId32, BuildStorage, + AccountId32, BuildStorage, FixedU128, }; use xcm::prelude::*; use xcm_builder::{DescribeAllTerminal, DescribeFamily, HashedDescription}; @@ -175,6 +176,7 @@ impl snowbridge_outbound_queue::Config for Test { type MaxMessagesPerBlock = MaxMessagesPerBlock; type GasMeter = ConstantGasMeter; type Balance = u128; + type PricingParameters = EthereumControl; type WeightToFee = IdentityFee; type WeightInfo = (); } @@ -188,6 +190,8 @@ parameter_types! { X2(GlobalConsensus(RelayNetwork::get().unwrap()), Parachain(1013)); } +pub const DOT: u128 = 10_000_000_000; + parameter_types! { pub TreasuryAccount: AccountId = PalletId(*b"py/trsry").into_account_truncating(); pub Fee: u64 = 1000; @@ -195,6 +199,12 @@ parameter_types! { pub const InitialFunding: u128 = 1_000_000_000_000; pub AssetHubParaId: ParaId = ParaId::new(1000); pub TestParaId: u32 = 2000; + pub Parameters: PricingParameters = PricingParameters { + exchange_rate: FixedU128::from_rational(1, 400), + fee_per_gas: gwei(20), + rewards: Rewards { local: 1 * DOT, remote: meth(1) } + }; + } #[cfg(feature = "runtime-benchmarks")] @@ -211,6 +221,7 @@ impl crate::Config for Test { type AgentIdOf = HashedDescription>; type TreasuryAccount = TreasuryAccount; type Token = Balances; + type DefaultPricingParameters = Parameters; type WeightInfo = (); #[cfg(feature = "runtime-benchmarks")] type Helper = (); diff --git a/parachain/pallets/control/src/tests.rs b/parachain/pallets/control/src/tests.rs index e4685219b5..1f742a0060 100644 --- a/parachain/pallets/control/src/tests.rs +++ b/parachain/pallets/control/src/tests.rs @@ -122,7 +122,7 @@ fn create_channel() { let _ = Balances::mint_into(&sovereign_account, 10000); assert_ok!(EthereumControl::create_agent(origin.clone())); - assert_ok!(EthereumControl::create_channel(origin, OperatingMode::Normal, 1)); + assert_ok!(EthereumControl::create_channel(origin, OperatingMode::Normal)); }); } @@ -138,10 +138,10 @@ fn create_channel_fail_already_exists() { let _ = Balances::mint_into(&sovereign_account, 10000); assert_ok!(EthereumControl::create_agent(origin.clone())); - assert_ok!(EthereumControl::create_channel(origin.clone(), OperatingMode::Normal, 1)); + assert_ok!(EthereumControl::create_channel(origin.clone(), OperatingMode::Normal)); assert_noop!( - EthereumControl::create_channel(origin, OperatingMode::Normal, 1), + EthereumControl::create_channel(origin, OperatingMode::Normal), Error::::ChannelAlreadyCreated ); }); @@ -155,7 +155,6 @@ fn create_channel_bad_origin() { EthereumControl::create_channel( make_xcm_origin(MultiLocation { parents: 1, interior: Here }), OperatingMode::Normal, - 1 ), BadOrigin, ); @@ -171,7 +170,6 @@ fn create_channel_bad_origin() { ), }), OperatingMode::Normal, - 1 ), BadOrigin, ); @@ -184,7 +182,6 @@ fn create_channel_bad_origin() { interior: X1(Junction::AccountId32 { network: None, id: [67u8; 32] }), }), OperatingMode::Normal, - 1 ), BadOrigin, ); @@ -194,7 +191,6 @@ fn create_channel_bad_origin() { EthereumControl::create_channel( RuntimeOrigin::signed([14; 32].into()), OperatingMode::Normal, - 1 ), BadOrigin ); @@ -215,7 +211,7 @@ fn update_channel() { // First create the channel let _ = Balances::mint_into(&sovereign_account, 10000); EthereumControl::create_agent(origin.clone()).unwrap(); - EthereumControl::create_channel(origin.clone(), OperatingMode::Normal, 1).unwrap(); + EthereumControl::create_channel(origin.clone(), OperatingMode::Normal).unwrap(); // Now try to update it assert_ok!(EthereumControl::update_channel(origin, OperatingMode::Normal, 2004)); @@ -311,7 +307,7 @@ fn force_update_channel() { // First create the channel let _ = Balances::mint_into(&sovereign_account, 10000); EthereumControl::create_agent(origin.clone()).unwrap(); - EthereumControl::create_channel(origin.clone(), OperatingMode::Normal, 1).unwrap(); + EthereumControl::create_channel(origin.clone(), OperatingMode::Normal).unwrap(); // Now try to force update it let force_origin = RuntimeOrigin::root(); @@ -516,7 +512,7 @@ fn charge_fee_for_transfer_native_from_agent() { // create_agent & create_channel first assert_ok!(EthereumControl::create_agent(origin.clone())); - assert_ok!(EthereumControl::create_channel(origin.clone(), OperatingMode::Normal, 1)); + assert_ok!(EthereumControl::create_channel(origin.clone(), OperatingMode::Normal)); // assert sovereign_balance decreased by only the base_fee let sovereign_balance_before = Balances::balance(&sovereign_account); @@ -549,3 +545,27 @@ fn charge_fee_for_upgrade() { assert_eq!(sovereign_balance, InitialFunding::get()); }); } + +#[test] +fn set_pricing_params_root_only() { + new_test_ext().execute_with(|| { + let origin = RuntimeOrigin::signed(AccountId32::from([0; 32])); + assert_noop!( + EthereumControl::set_pricing_parameters(origin, Parameters::get()), + DispatchError::BadOrigin, + ); + }) +} + +#[test] +fn set_fee_config_invalid() { + new_test_ext().execute_with(|| { + let origin = RuntimeOrigin::root(); + let mut params = Parameters::get(); + params.rewards.local = 0; + assert_noop!( + EthereumControl::set_pricing_parameters(origin, params), + Error::::InvalidPricingParameters + ); + }) +} diff --git a/parachain/pallets/inbound-queue/src/lib.rs b/parachain/pallets/inbound-queue/src/lib.rs index b3a61ed8f6..bdd367ad23 100644 --- a/parachain/pallets/inbound-queue/src/lib.rs +++ b/parachain/pallets/inbound-queue/src/lib.rs @@ -57,7 +57,7 @@ use xcm::prelude::{ use snowbridge_core::{ inbound::{Message, VerificationError, Verifier}, - sibling_sovereign_account, BasicOperatingMode, Channel, ChannelId, ChannelLookup, ParaId, + sibling_sovereign_account, BasicOperatingMode, Channel, ChannelId, ParaId, StaticLookup, }; use snowbridge_router_primitives::{ inbound, @@ -81,6 +81,7 @@ pub mod pallet { use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; + use snowbridge_core::PricingParameters; #[pallet::pallet] pub struct Pallet(_); @@ -100,10 +101,6 @@ pub mod pallet { /// Message relayers are rewarded with this asset type Token: Mutate; - /// The amount to reward message relayers - #[pallet::constant] - type Reward: Get>; - /// XCM message sender type XcmSender: SendXcm; @@ -117,7 +114,9 @@ pub mod pallet { Balance = BalanceOf, >; - type ChannelLookup: ChannelLookup; + type ChannelLookup: StaticLookup; + + type PricingParameters: Get>>; type WeightInfo: WeightInfo; @@ -230,7 +229,7 @@ pub mod pallet { ensure!(T::GatewayAddress::get() == envelope.gateway, Error::::InvalidGateway); // Retrieve the registered channel for this message - let channel: Channel = + let channel = T::ChannelLookup::lookup(envelope.channel_id).ok_or(Error::::InvalidChannel)?; // Verify message nonce @@ -246,6 +245,8 @@ pub mod pallet { } })?; + let pricing_parameters = T::PricingParameters::get(); + // Reward relayer from the sovereign account of the destination parachain // Expected to fail if sovereign account has no funds let sovereign_account = sibling_sovereign_account::(channel.para_id); @@ -253,7 +254,7 @@ pub mod pallet { T::Token::transfer( &sovereign_account, &who, - refund.saturating_add(T::Reward::get()), + refund.saturating_add(pricing_parameters.rewards.local), Preservation::Preserve, )?; diff --git a/parachain/pallets/inbound-queue/src/test.rs b/parachain/pallets/inbound-queue/src/test.rs index 75aebb1074..749ab2915c 100644 --- a/parachain/pallets/inbound-queue/src/test.rs +++ b/parachain/pallets/inbound-queue/src/test.rs @@ -9,13 +9,17 @@ use frame_support::{ }; use hex_literal::hex; use snowbridge_beacon_primitives::{Fork, ForkVersions}; -use snowbridge_core::inbound::{Log, Proof, VerificationError}; +use snowbridge_core::{ + gwei, + inbound::{Log, Proof, VerificationError}, + meth, Channel, ChannelId, PricingParameters, Rewards, StaticLookup, +}; use snowbridge_router_primitives::inbound::MessageToXcm; use sp_core::{H160, H256}; use sp_keyring::AccountKeyring as Keyring; use sp_runtime::{ traits::{BlakeTwo256, IdentifyAccount, IdentityLookup, Verify}, - BuildStorage, DispatchError, MultiSignature, TokenError, + BuildStorage, DispatchError, FixedU128, MultiSignature, TokenError, }; use sp_std::convert::From; use xcm::v3::{prelude::*, MultiAssets, SendXcm}; @@ -169,15 +173,24 @@ impl SendXcm for MockXcmSender { } } +parameter_types! { + pub const OwnParaId: ParaId = ParaId::new(1013); + pub Parameters: PricingParameters = PricingParameters { + exchange_rate: FixedU128::from_rational(1, 400), + fee_per_gas: gwei(20), + rewards: Rewards { local: 1 * DOT, remote: meth(1) } + }; +} + +pub const DOT: u128 = 10_000_000_000; + pub struct MockChannelLookup; -impl ChannelLookup for MockChannelLookup { - fn lookup(channel_id: ChannelId) -> Option { - if channel_id != - hex!("c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539").into() - { - return None - } - Some(Channel { agent_id: H256::zero().into(), para_id: 1000.into() }) +impl StaticLookup for MockChannelLookup { + type Source = ChannelId; + type Target = Channel; + + fn lookup(_: Self::Source) -> Option { + Some(Channel { agent_id: H256::zero().into(), para_id: Default::default() }) } } @@ -185,7 +198,6 @@ impl inbound_queue::Config for Test { type RuntimeEvent = RuntimeEvent; type Verifier = MockVerifier; type Token = Balances; - type Reward = ConstU128<100>; type XcmSender = MockXcmSender; type WeightInfo = (); type GatewayAddress = GatewayAddress; @@ -193,10 +205,10 @@ impl inbound_queue::Config for Test { CreateAssetCall, CreateAssetExecutionFee, CreateAssetDeposit, - SendTokenExecutionFee, AccountId, Balance, >; + type PricingParameters = Parameters; type ChannelLookup = MockChannelLookup; #[cfg(feature = "runtime-benchmarks")] type Helper = Test; diff --git a/parachain/pallets/outbound-queue/src/lib.rs b/parachain/pallets/outbound-queue/src/lib.rs index 0f65e4f193..6bdbdb87b2 100644 --- a/parachain/pallets/outbound-queue/src/lib.rs +++ b/parachain/pallets/outbound-queue/src/lib.rs @@ -99,16 +99,17 @@ use codec::Decode; use cumulus_primitives_core::AggregateMessageOrigin; use frame_support::{ storage::StorageStreamIter, - traits::{tokens::Balance, EnqueueMessage, Get, ProcessMessageError}, + traits::{tokens::Balance, Defensive, EnqueueMessage, Get, ProcessMessageError}, weights::{Weight, WeightToFee}, }; use snowbridge_core::{ + gwei, meth, outbound::{Command, Fee, GasMeter, QueuedMessage, VersionedQueuedMessage, ETHER_DECIMALS}, - BasicOperatingMode, ChannelId, GWEI, METH, + BasicOperatingMode, ChannelId, }; use snowbridge_outbound_queue_merkle_tree::merkle_root; pub use snowbridge_outbound_queue_merkle_tree::MerkleProof; -use sp_core::H256; +use sp_core::{H256, U256}; use sp_runtime::{ traits::{CheckedDiv, Hash}, FixedPointNumber, @@ -124,6 +125,7 @@ pub mod pallet { use super::*; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; + use snowbridge_core::PricingParameters; use sp_arithmetic::FixedU128; #[pallet::pallet] @@ -154,6 +156,8 @@ pub mod pallet { #[pallet::constant] type MaxMessagesPerBlock: Get; + type PricingParameters: Get>; + /// Convert a weight value into a deductible fee based. type WeightToFee: WeightToFee; @@ -201,6 +205,8 @@ pub mod pallet { Halted, // Invalid fee config InvalidFeeConfig, + /// Invalid Channel + InvalidChannel, } /// Messages to be committed in the current block. This storage value is killed in @@ -230,22 +236,6 @@ pub mod pallet { #[pallet::getter(fn operating_mode)] pub type OperatingMode = StorageValue<_, BasicOperatingMode, ValueQuery>; - #[pallet::storage] - #[pallet::getter(fn fee_config)] - pub type FeeConfig = StorageValue<_, FeeConfigRecord, ValueQuery, DefaultFeeConfig>; - - #[pallet::type_value] - pub fn DefaultFeeConfig() -> FeeConfigRecord { - // When the FeeConfigRecord is updated, so should this fee constant on asset hub: - // polkadot-sdk/cumulus/parachains/common/src/snowbridge_config.rs - FeeConfigRecord { - exchange_rate: FixedU128::saturating_from_rational(1, 400), - fee_per_gas: 20 * GWEI, - #[allow(clippy::identity_op)] - reward: 1 * METH, - } - } - #[pallet::hooks] impl Hooks> for Pallet where @@ -283,16 +273,6 @@ pub mod pallet { Self::deposit_event(Event::OperatingModeChanged { mode }); Ok(()) } - - #[pallet::call_index(1)] - #[pallet::weight((T::DbWeight::get().reads_writes(1, 1), DispatchClass::Operational))] - pub fn set_fee_config(origin: OriginFor, fee_config: FeeConfigRecord) -> DispatchResult { - ensure_root(origin)?; - fee_config.validate().map_err(|_| Error::::InvalidFeeConfig)?; - FeeConfig::::put(fee_config); - Self::deposit_event(Event::FeeConfigChanged { fee_config }); - Ok(()) - } } impl Pallet { @@ -337,13 +317,19 @@ pub mod pallet { let queued_message: QueuedMessage = versioned_queued_message.try_into().map_err(|_| Unsupported)?; + let pricing_params = T::PricingParameters::get(); + let next_nonce = Nonce::::get(queued_message.channel_id).saturating_add(1); let command = queued_message.command.index(); let params = queued_message.command.abi_encode(); - let max_dispatch_gas = T::GasMeter::maximum_required(&queued_message.command) as u128; - let max_refund = Self::calculate_maximum_gas_refund(&queued_message.command); - let reward = Self::fee_config().reward; + let max_dispatch_gas = + T::GasMeter::maximum_dispatch_gas_used_at_most(&queued_message.command); + let max_refund = Self::calculate_maximum_gas_refund( + &queued_message.command, + pricing_params.fee_per_gas, + ); + let reward = pricing_params.rewards.remote; // Construct the final committed message let message = CommittedMessage { @@ -352,8 +338,8 @@ pub mod pallet { command, params, max_dispatch_gas, - max_refund, - reward, + max_refund: max_refund.try_into().defensive_unwrap_or(u128::MAX), + reward: reward.try_into().defensive_unwrap_or(u128::MAX), id: queued_message.id, }; @@ -373,39 +359,43 @@ pub mod pallet { Ok(true) } - /// Maximum overall gas required for delivering a message - pub(crate) fn maximum_overall_required_gas(command: &Command) -> u64 { - T::GasMeter::MAXIMUM_BASE_GAS + T::GasMeter::maximum_required(command) - } - - /// Calculate fee in native currency for delivering a message. - pub(crate) fn calculate_fee(command: &Command) -> Fee { - let max_gas = Self::maximum_overall_required_gas(command); - let remote = Self::calculate_remote_fee( - max_gas, - Self::fee_config().fee_per_gas, - Self::fee_config().reward, + /// Calculate total fee in native currency to cover all costs of delivering a message to the + /// remote destination. See module-level documentation for more details. + pub(crate) fn calculate_fee( + gas_used_at_most: u64, + params: PricingParameters, + ) -> Fee { + // Remote fee in ether + let fee = Self::calculate_remote_fee( + gas_used_at_most, + params.fee_per_gas, + params.rewards.remote, ); - let remote = FixedU128::from(remote) - .checked_div(&Self::fee_config().exchange_rate) + // downcast to u128 + let fee: u128 = fee.try_into().defensive_unwrap_or(u128::MAX); + + // convert to local currency + let fee = FixedU128::from(fee) + .checked_div(¶ms.exchange_rate) .expect("exchange rate is not zero; qed") .into_inner() .checked_div(FixedU128::accuracy()) .expect("accuracy is not zero; qed"); - let remote = Self::convert_from_ether_decimals(remote); + // adjust fixed point to match local currency + let fee = Self::convert_from_ether_decimals(fee); - Fee::from((Self::calculate_local_fee(), remote)) + Fee::from((Self::calculate_local_fee(), fee)) } /// Calculate fee in remote currency for dispatching a message on Ethereum pub(crate) fn calculate_remote_fee( - max_gas_required: u64, - fee_per_gas: u128, - reward: u128, - ) -> u128 { - fee_per_gas.saturating_mul(max_gas_required.into()).saturating_add(reward) + gas_used_at_most: u64, + fee_per_gas: U256, + reward: U256, + ) -> U256 { + fee_per_gas.saturating_mul(gas_used_at_most.into()).saturating_add(reward) } /// The local component of the message processing fees in native currency @@ -416,9 +406,11 @@ pub mod pallet { } /// Maximum refund in Ether for delivering a message - pub(crate) fn calculate_maximum_gas_refund(command: &Command) -> u128 { - let max_gas = Self::maximum_overall_required_gas(command); - Self::fee_config().fee_per_gas.saturating_mul(max_gas.into()) + pub(crate) fn calculate_maximum_gas_refund(command: &Command, fee_per_gas: U256) -> U256 { + // Maximum overall gas required for delivering a message + let max_gas = T::GasMeter::MAXIMUM_BASE_GAS + + T::GasMeter::maximum_dispatch_gas_used_at_most(command); + fee_per_gas.saturating_mul(max_gas.into()) } // 1 DOT has 10 digits of precision diff --git a/parachain/pallets/outbound-queue/src/mock.rs b/parachain/pallets/outbound-queue/src/mock.rs index 34c7ce7730..4504e48798 100644 --- a/parachain/pallets/outbound-queue/src/mock.rs +++ b/parachain/pallets/outbound-queue/src/mock.rs @@ -8,11 +8,16 @@ use frame_support::{ weights::IdentityFee, }; -use snowbridge_core::{outbound::*, ParaId, PRIMARY_GOVERNANCE_CHANNEL}; +use snowbridge_core::{ + gwei, meth, + outbound::*, + pricing::{PricingParameters, Rewards}, + Channel, ChannelId, ParaId, PRIMARY_GOVERNANCE_CHANNEL, +}; use sp_core::{ConstU32, ConstU8, H160, H256}; use sp_runtime::{ traits::{BlakeTwo256, IdentityLookup, Keccak256}, - AccountId32, BuildStorage, + AccountId32, BuildStorage, FixedU128, }; type Block = frame_system::mocking::MockBlock; @@ -77,8 +82,15 @@ impl pallet_message_queue::Config for Test { parameter_types! { pub const OwnParaId: ParaId = ParaId::new(1013); + pub Parameters: PricingParameters = PricingParameters { + exchange_rate: FixedU128::from_rational(1, 400), + fee_per_gas: gwei(20), + rewards: Rewards { local: 1 * DOT, remote: meth(1) } + }; } +pub const DOT: u128 = 10_000_000_000; + impl crate::Config for Test { type RuntimeEvent = RuntimeEvent; type Hashing = Keccak256; @@ -88,6 +100,7 @@ impl crate::Config for Test { type MaxMessagesPerBlock = ConstU32<20>; type GasMeter = ConstantGasMeter; type Balance = u128; + type PricingParameters = Parameters; type WeightToFee = IdentityFee; type WeightInfo = (); } diff --git a/parachain/pallets/outbound-queue/src/send_message_impl.rs b/parachain/pallets/outbound-queue/src/send_message_impl.rs index 16571e8fbb..f6c5188f94 100644 --- a/parachain/pallets/outbound-queue/src/send_message_impl.rs +++ b/parachain/pallets/outbound-queue/src/send_message_impl.rs @@ -54,7 +54,8 @@ where .id .unwrap_or_else(|| unique((message.channel_id, &message.command)).into()); - let fee = Self::calculate_fee(&message.command); + let gas_used_at_most = T::GasMeter::maximum_gas_used_at_most(&message.command); + let fee = Self::calculate_fee(gas_used_at_most, T::PricingParameters::get()); let queued_message: VersionedQueuedMessage = QueuedMessage { id: message_id, diff --git a/parachain/pallets/outbound-queue/src/test.rs b/parachain/pallets/outbound-queue/src/test.rs index 3dbcc9f8a9..7e49db16f1 100644 --- a/parachain/pallets/outbound-queue/src/test.rs +++ b/parachain/pallets/outbound-queue/src/test.rs @@ -49,17 +49,6 @@ fn submit_message_fail_too_large() { }); } -#[test] -fn calculate_fees() { - new_tester().execute_with(|| { - let command = mock_message(1000).command; - let fee = OutboundQueue::calculate_fee(&command); - assert_eq!(fee.remote, 2200000000000); - - println!("Total fee: {}", fee.total()) - }); -} - #[test] fn convert_from_ether_decimals() { assert_eq!( @@ -124,42 +113,6 @@ fn process_message_fails_on_overweight_message() { }) } -#[test] -fn set_operating_mode_root_only() { - new_tester().execute_with(|| { - let origin = RuntimeOrigin::signed(AccountId32::from([0; 32])); - assert_noop!( - OutboundQueue::set_operating_mode(origin, BasicOperatingMode::Halted), - DispatchError::BadOrigin, - ); - }) -} - -#[test] -fn set_fee_config_root_only() { - new_tester().execute_with(|| { - let origin = RuntimeOrigin::signed(AccountId32::from([0; 32])); - assert_noop!( - OutboundQueue::set_fee_config(origin, DefaultFeeConfig::get()), - DispatchError::BadOrigin, - ); - }) -} - -#[test] -fn set_fee_config_invalid() { - new_tester().execute_with(|| { - let origin = RuntimeOrigin::root(); - assert_noop!( - OutboundQueue::set_fee_config( - origin, - FeeConfigRecord { exchange_rate: (1, 1).into(), reward: 0, fee_per_gas: 0 } - ), - Error::::InvalidFeeConfig - ); - }) -} - // Governance messages should be able to bypass a halted operating mode // Other message sends should fail when halted #[test] diff --git a/parachain/pallets/outbound-queue/src/types.rs b/parachain/pallets/outbound-queue/src/types.rs index 8afb9c450d..1b2b3aeaea 100644 --- a/parachain/pallets/outbound-queue/src/types.rs +++ b/parachain/pallets/outbound-queue/src/types.rs @@ -4,7 +4,7 @@ use frame_support::traits::ProcessMessage; use scale_info::TypeInfo; use serde::{Deserialize, Serialize}; use sp_arithmetic::FixedU128; -use sp_core::H256; +use sp_core::{H256, U256}; use sp_runtime::{traits::Zero, RuntimeDebug}; use sp_std::prelude::*; @@ -23,16 +23,20 @@ pub struct CommittedMessage { /// Message channel pub channel_id: ChannelId, /// Unique nonce to prevent replaying messages + #[codec(compact)] pub nonce: u64, /// Command to execute in the Gateway contract pub command: u8, /// Params for the command pub params: Vec, /// Maximum gas allowed for message dispatch - pub max_dispatch_gas: u128, + #[codec(compact)] + pub max_dispatch_gas: u64, /// Maximum gas refund for message relayer + #[codec(compact)] pub max_refund: u128, /// Reward in ether for delivering this message, in addition to the gas refund + #[codec(compact)] pub reward: u128, /// Message ID (Used for tracing messages across route, has no role in consensus) pub id: H256, diff --git a/parachain/primitives/core/src/lib.rs b/parachain/primitives/core/src/lib.rs index a07fef34be..05c1c9b1cf 100644 --- a/parachain/primitives/core/src/lib.rs +++ b/parachain/primitives/core/src/lib.rs @@ -11,12 +11,14 @@ mod tests; pub mod inbound; pub mod operating_mode; pub mod outbound; +pub mod pricing; pub mod ringbuffer; pub use polkadot_parachain_primitives::primitives::{ Id as ParaId, IsSystem, Sibling as SiblingParaId, }; pub use ringbuffer::{RingBufferMap, RingBufferMapImpl}; +pub use sp_core::U256; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::traits::Contains; @@ -32,6 +34,8 @@ use xcm::prelude::{Junction::Parachain, Junctions::X1, MultiLocation}; pub type AgentId = H256; pub use operating_mode::BasicOperatingMode; +pub use pricing::{PricingParameters, Rewards}; + pub fn sibling_sovereign_account(para_id: ParaId) -> T::AccountId where T: frame_system::Config, @@ -50,9 +54,19 @@ impl Contains for AllowSiblingsOnly { } } -pub const GWEI: u128 = 1_000_000_000; -pub const METH: u128 = 1_000_000_000_000_000; -pub const ETH: u128 = 1_000_000_000_000_000_000; +pub fn gwei(x: u128) -> U256 { + U256::from(1_000_000_000u128).saturating_mul(x.into()) +} + +pub fn meth(x: u128) -> U256 { + U256::from(1_000_000_000_000_000u128).saturating_mul(x.into()) +} + +pub fn eth(x: u128) -> U256 { + U256::from(1_000_000_000_000_000_000u128).saturating_mul(x.into()) +} + +pub const ROC: u128 = 1_000_000_000_000; /// Identifier for a message channel #[derive( @@ -123,8 +137,13 @@ pub struct Channel { pub para_id: ParaId, } -pub trait ChannelLookup { - fn lookup(channel_id: ChannelId) -> Option; +pub trait StaticLookup { + /// Type to lookup from. + type Source; + /// Type to lookup into. + type Target; + /// Attempt a lookup. + fn lookup(s: Self::Source) -> Option; } /// Channel for high-priority governance commands diff --git a/parachain/primitives/core/src/outbound.rs b/parachain/primitives/core/src/outbound.rs index 24e91fcdf4..68a3f84910 100644 --- a/parachain/primitives/core/src/outbound.rs +++ b/parachain/primitives/core/src/outbound.rs @@ -30,7 +30,7 @@ impl> From for VersionedQueuedMessage { } mod v1 { - use crate::ChannelId; + use crate::{pricing::UD60x18, ChannelId}; use codec::{Decode, Encode}; use ethabi::Token; use scale_info::TypeInfo; @@ -94,8 +94,6 @@ mod v1 { agent_id: H256, /// Initial operating mode mode: OperatingMode, - /// The fee to charge users for outbound messaging to Polkadot - outbound_fee: u128, }, /// Update the configuration of a channel UpdateChannel { @@ -103,8 +101,6 @@ mod v1 { channel_id: ChannelId, /// The new operating mode mode: OperatingMode, - /// The new fee to charge users for outbound messaging to Polkadot - outbound_fee: u128, }, /// Set the global operating mode of the Gateway contract SetOperatingMode { @@ -127,6 +123,13 @@ mod v1 { /// The fee for send token to para chain send: u128, }, + /// Set pricing parameters + SetPricingParameters { + // relative ETH value + exchange_rate: UD60x18, + // Cost of delivering a message from Ethereum to BridgeHub, in ROC/KSM/DOT + delivery_cost: u128, + }, } impl Command { @@ -141,6 +144,7 @@ mod v1 { Command::SetOperatingMode { .. } => 5, Command::TransferNativeFromAgent { .. } => 6, Command::SetTokenTransferFees { .. } => 7, + Command::SetPricingParameters { .. } => 8, } } @@ -164,18 +168,16 @@ mod v1 { ethabi::encode(&[Token::Tuple(vec![Token::FixedBytes( agent_id.as_bytes().to_owned(), )])]), - Command::CreateChannel { channel_id, agent_id, mode, outbound_fee } => + Command::CreateChannel { channel_id, agent_id, mode } => ethabi::encode(&[Token::Tuple(vec![ Token::FixedBytes(channel_id.as_ref().to_owned()), Token::FixedBytes(agent_id.as_bytes().to_owned()), Token::Uint(U256::from((*mode) as u64)), - Token::Uint(U256::from(*outbound_fee)), ])]), - Command::UpdateChannel { channel_id, mode, outbound_fee } => + Command::UpdateChannel { channel_id, mode } => ethabi::encode(&[Token::Tuple(vec![ Token::FixedBytes(channel_id.as_ref().to_owned()), Token::Uint(U256::from((*mode) as u64)), - Token::Uint(U256::from(*outbound_fee)), ])]), Command::SetOperatingMode { mode } => ethabi::encode(&[Token::Tuple(vec![Token::Uint(U256::from((*mode) as u64))])]), @@ -190,6 +192,11 @@ mod v1 { Token::Uint(U256::from(*register)), Token::Uint(U256::from(*send)), ])]), + Command::SetPricingParameters { exchange_rate, delivery_cost } => + ethabi::encode(&[Token::Tuple(vec![ + Token::Uint(exchange_rate.clone().into_inner()), + Token::Uint(U256::from(*delivery_cost)), + ])]), } } } @@ -319,6 +326,8 @@ pub enum SendError { MessageTooLarge, /// The bridge has been halted for maintenance Halted, + /// Invalid Channel + InvalidChannel, } pub trait GasMeter { @@ -326,9 +335,13 @@ pub trait GasMeter { /// the command within the message const MAXIMUM_BASE_GAS: u64; - /// Measures the maximum amount of gas a command will require to dispatch. Does not include the - /// base cost of message submission. - fn maximum_required(command: &Command) -> u64; + fn maximum_gas_used_at_most(command: &Command) -> u64 { + Self::MAXIMUM_BASE_GAS + Self::maximum_dispatch_gas_used_at_most(command) + } + + /// Measures the maximum amount of gas a command payload will require to dispatch, AFTER + /// validation & verification. + fn maximum_dispatch_gas_used_at_most(command: &Command) -> u64; } /// A meter that assigns a constant amount of gas for the execution of a command @@ -344,7 +357,7 @@ pub struct ConstantGasMeter; impl GasMeter for ConstantGasMeter { const MAXIMUM_BASE_GAS: u64 = 125_000; - fn maximum_required(command: &Command) -> u64 { + fn maximum_dispatch_gas_used_at_most(command: &Command) -> u64 { match command { Command::CreateAgent { .. } => 275_000, Command::CreateChannel { .. } => 100_000, @@ -370,6 +383,7 @@ impl GasMeter for ConstantGasMeter { 50_000 + initializer_max_gas }, Command::SetTokenTransferFees { .. } => 60_000, + Command::SetPricingParameters { .. } => 60_000, } } } @@ -377,7 +391,7 @@ impl GasMeter for ConstantGasMeter { impl GasMeter for () { const MAXIMUM_BASE_GAS: u64 = 1; - fn maximum_required(_: &Command) -> u64 { + fn maximum_dispatch_gas_used_at_most(_: &Command) -> u64 { 1 } } diff --git a/parachain/primitives/core/src/pricing.rs b/parachain/primitives/core/src/pricing.rs new file mode 100644 index 0000000000..2e30a25b14 --- /dev/null +++ b/parachain/primitives/core/src/pricing.rs @@ -0,0 +1,67 @@ +use codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; +use sp_arithmetic::traits::{BaseArithmetic, Unsigned, Zero}; +use sp_core::U256; +use sp_runtime::{FixedU128, RuntimeDebug}; +use sp_std::prelude::*; + +#[derive(Clone, Encode, Decode, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo)] +pub struct PricingParameters { + /// ETH/DOT exchange rate + pub exchange_rate: FixedU128, + /// Relayer rewards + pub rewards: Rewards, + /// Ether (wei) fee per gas unit + pub fee_per_gas: U256, +} + +#[derive(Clone, Encode, Decode, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo)] +pub struct Rewards { + /// Local reward in DOT + pub local: Balance, + /// Remote reward in ETH (wei) + pub remote: U256, +} + +#[derive(RuntimeDebug)] +pub struct InvalidPricingParameters; + +impl PricingParameters +where + Balance: BaseArithmetic + Unsigned + Copy, +{ + pub fn validate(&self) -> Result<(), InvalidPricingParameters> { + if self.exchange_rate == FixedU128::zero() { + return Err(InvalidPricingParameters) + } + if self.fee_per_gas == U256::zero() { + return Err(InvalidPricingParameters) + } + if self.rewards.local.is_zero() { + return Err(InvalidPricingParameters) + } + if self.rewards.remote.is_zero() { + return Err(InvalidPricingParameters) + } + Ok(()) + } +} + +/// Holder for fixed point number implemented in https://github.com/PaulRBerg/prb-math +#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +#[cfg_attr(feature = "std", derive(PartialEq))] +pub struct UD60x18(U256); + +impl From for UD60x18 { + fn from(value: FixedU128) -> Self { + // Both FixedU128 and UD60x18 have 18 decimal places + let inner: u128 = value.into_inner(); + UD60x18(inner.into()) + } +} + +impl UD60x18 { + pub fn into_inner(self) -> U256 { + self.0 + } +} diff --git a/parachain/primitives/router/src/inbound/mod.rs b/parachain/primitives/router/src/inbound/mod.rs index f222823a62..873e1902d1 100644 --- a/parachain/primitives/router/src/inbound/mod.rs +++ b/parachain/primitives/router/src/inbound/mod.rs @@ -46,9 +46,6 @@ pub enum Command { RegisterToken { /// The address of the ERC20 token to be bridged over to AssetHub token: H160, - /// The fee for executing the XCM on AssetHub - /// Includes the XCM fee and the registration deposit - fee: u128, }, /// Send a token to AssetHub or another parachain SendToken { @@ -92,21 +89,18 @@ pub struct MessageToXcm< CreateAssetCall, CreateAssetExecutionFee, CreateAssetDeposit, - SendTokenExecutionFee, AccountId, Balance, > where CreateAssetCall: Get, CreateAssetExecutionFee: Get, CreateAssetDeposit: Get, - SendTokenExecutionFee: Get, Balance: BalanceT, { _phantom: PhantomData<( CreateAssetCall, CreateAssetExecutionFee, CreateAssetDeposit, - SendTokenExecutionFee, AccountId, Balance, )>, @@ -129,26 +123,13 @@ pub trait ConvertMessage { pub type CallIndex = [u8; 2]; -impl< - CreateAssetCall, - CreateAssetExecutionFee, - CreateAssetDeposit, - SendTokenExecutionFee, - AccountId, - Balance, - > ConvertMessage - for MessageToXcm< - CreateAssetCall, - CreateAssetExecutionFee, - CreateAssetDeposit, - SendTokenExecutionFee, - AccountId, - Balance, - > where +impl + ConvertMessage + for MessageToXcm +where CreateAssetCall: Get, CreateAssetExecutionFee: Get, CreateAssetDeposit: Get, - SendTokenExecutionFee: Get, Balance: BalanceT + From, AccountId: Into<[u8; 32]>, { @@ -161,32 +142,18 @@ impl< match message { V1(MessageV1 { chain_id, command: RegisterToken { token } }) => Ok(Self::convert_register_token(chain_id, token)), - V1(MessageV1 { chain_id, command: SendToken { token, destination, amount } }) => - Ok(Self::convert_send_token(chain_id, token, destination, amount)), + V1(MessageV1 { chain_id, command: SendToken { token, destination, amount, fee } }) => + Ok(Self::convert_send_token(chain_id, token, destination, amount, fee)), } } } -impl< - CreateAssetCall, - CreateAssetExecutionFee, - CreateAssetDeposit, - SendTokenExecutionFee, - AccountId, - Balance, - > - MessageToXcm< - CreateAssetCall, - CreateAssetExecutionFee, - CreateAssetDeposit, - SendTokenExecutionFee, - AccountId, - Balance, - > where +impl + MessageToXcm +where CreateAssetCall: Get, CreateAssetExecutionFee: Get, CreateAssetDeposit: Get, - SendTokenExecutionFee: Get, Balance: BalanceT + From, AccountId: Into<[u8; 32]>, { @@ -241,41 +208,41 @@ impl< token: H160, destination: Destination, amount: u128, + asset_hub_fee: u128, ) -> (Xcm<()>, Balance) { let network = Ethereum { chain_id }; - let fee_amount = SendTokenExecutionFee::get(); - let fee: MultiAsset = (MultiLocation::parent(), fee_amount).into(); + let asset_hub_fee_asset: MultiAsset = (MultiLocation::parent(), asset_hub_fee).into(); let asset: MultiAsset = (Self::convert_token_address(network, token), amount).into(); - let (dest_para_id, beneficiary, total_fee_amount) = match destination { + let (dest_para_id, beneficiary, dest_para_fee) = match destination { // Final destination is a 32-byte account on AssetHub Destination::AccountId32 { id } => ( None, MultiLocation { parents: 0, interior: X1(AccountId32 { network: None, id }) }, - // Total fee needs to cover execution only on AssetHub - fee_amount, + 0, ), // Final destination is a 32-byte account on a sibling of AssetHub - Destination::ForeignAccountId32 { para_id, id } => ( + Destination::ForeignAccountId32 { para_id, id, fee } => ( Some(para_id), MultiLocation { parents: 0, interior: X1(AccountId32 { network: None, id }) }, // Total fee needs to cover execution on AssetHub and Sibling - fee_amount * 2, + fee, ), // Final destination is a 20-byte account on a sibling of AssetHub - Destination::ForeignAccountId20 { para_id, id } => ( + Destination::ForeignAccountId20 { para_id, id, fee } => ( Some(para_id), MultiLocation { parents: 0, interior: X1(AccountKey20 { network: None, key: id }) }, // Total fee needs to cover execution on AssetHub and Sibling - fee_amount * 2, + fee, ), }; - let total_fee: MultiAsset = (MultiLocation::parent(), total_fee_amount).into(); + let total_fees = asset_hub_fee.saturating_add(dest_para_fee); + let total_fee_asset: MultiAsset = (MultiLocation::parent(), total_fees).into(); let mut instructions = vec![ - ReceiveTeleportedAsset(total_fee.into()), - BuyExecution { fees: fee.clone(), weight_limit: Unlimited }, + ReceiveTeleportedAsset(total_fee_asset.into()), + BuyExecution { fees: asset_hub_fee_asset, weight_limit: Unlimited }, UniversalOrigin(GlobalConsensus(network)), ReserveAssetDeposited(asset.clone().into()), ClearOrigin, @@ -283,14 +250,17 @@ impl< match dest_para_id { Some(dest_para_id) => { + let dest_para_fee_asset: MultiAsset = + (MultiLocation::parent(), dest_para_fee).into(); + instructions.extend(vec![ // Perform a deposit reserve to send to destination chain. DepositReserveAsset { - assets: Definite(vec![fee.clone(), asset.clone()].into()), + assets: Definite(vec![dest_para_fee_asset.clone(), asset.clone()].into()), dest: MultiLocation { parents: 1, interior: X1(Parachain(dest_para_id)) }, xcm: vec![ // Buy execution on target. - BuyExecution { fees: fee, weight_limit: Unlimited }, + BuyExecution { fees: dest_para_fee_asset, weight_limit: Unlimited }, // Deposit asset to beneficiary. DepositAsset { assets: Definite(asset.into()), beneficiary }, ] @@ -306,7 +276,7 @@ impl< }, } - (instructions.into(), total_fee_amount.into()) + (instructions.into(), total_fees.into()) } // Convert ERC20 token address to a Multilocation that can be understood by Assets Hub. From 26164247724bc4ed2b0447aa0300ddb669962fef Mon Sep 17 00:00:00 2001 From: Vincent Geddes Date: Mon, 27 Nov 2023 11:37:42 +0200 Subject: [PATCH 08/38] rename Cost to Costs --- contracts/src/Assets.sol | 20 ++++++++--------- contracts/src/Gateway.sol | 25 ++++++++++----------- contracts/src/Types.sol | 22 ++++++------------ contracts/src/interfaces/IGateway.sol | 4 ++-- contracts/test/Gateway.t.sol | 1 - contracts/test/mocks/GatewayUpgradeMock.sol | 2 +- 6 files changed, 32 insertions(+), 42 deletions(-) diff --git a/contracts/src/Assets.sol b/contracts/src/Assets.sol index bc89c362e8..28e402d5fa 100644 --- a/contracts/src/Assets.sol +++ b/contracts/src/Assets.sol @@ -9,7 +9,7 @@ import {SafeTokenTransferFrom} from "./utils/SafeTransfer.sol"; import {AssetsStorage} from "./storage/AssetsStorage.sol"; import {SubstrateTypes} from "./SubstrateTypes.sol"; -import {ParaID, MultiAddress, Ticket, Cost} from "./Types.sol"; +import {ParaID, MultiAddress, Ticket, Costs} from "./Types.sol"; import {Address} from "./utils/Address.sol"; /// @title Library for implementing Ethereum->Polkadot ERC20 transfers. @@ -39,7 +39,7 @@ library Assets { function sendTokenCosts(ParaID assetHubParaID, ParaID destinationChain, uint128 destinationChainFee) external view - returns (Cost memory costs) + returns (Costs memory costs) { return _sendTokenCosts(assetHubParaID, destinationChain, destinationChainFee); } @@ -47,17 +47,17 @@ library Assets { function _sendTokenCosts(ParaID assetHubParaID, ParaID destinationChain, uint128 destinationChainFee) internal view - returns (Cost memory cost) + returns (Costs memory costs) { AssetsStorage.Layout storage $ = AssetsStorage.layout(); if (assetHubParaID == destinationChain) { - cost.remote = $.assetHubReserveTransferFee; + costs.foreign = $.assetHubReserveTransferFee; } else { // If the final destination chain is not AssetHub, then the fee needs to additionally // include the cost of executing an XCM on the final destination parachain. - cost.remote = $.assetHubReserveTransferFee + destinationChainFee; + costs.foreign = $.assetHubReserveTransferFee + destinationChainFee; } - cost.local = 0; + costs.native = 0; } function sendToken( @@ -111,14 +111,14 @@ library Assets { } - function registerTokenCosts() external view returns (Cost memory costs) { + function registerTokenCosts() external view returns (Costs memory costs) { return _registerTokenCosts(); } - function _registerTokenCosts() internal view returns (Cost memory costs) { + function _registerTokenCosts() internal view returns (Costs memory costs) { AssetsStorage.Layout storage $ = AssetsStorage.layout(); - costs.remote = $.assetHubCreateAssetFee; - costs.local = $.registerTokenFee; + costs.foreign = $.assetHubCreateAssetFee; + costs.native = $.registerTokenFee; } /// @dev Enqueues a create native token message to substrate. diff --git a/contracts/src/Gateway.sol b/contracts/src/Gateway.sol index 6de385fcdc..8b3e45cece 100644 --- a/contracts/src/Gateway.sol +++ b/contracts/src/Gateway.sol @@ -8,7 +8,7 @@ import {Verification} from "./Verification.sol"; import {Assets} from "./Assets.sol"; import {AgentExecutor} from "./AgentExecutor.sol"; import {Agent} from "./Agent.sol"; -import {Channel, ChannelID, InboundMessage, OperatingMode, ParaID, Command, MultiAddress, Ticket, Cost} from "./Types.sol"; +import {Channel, ChannelID, InboundMessage, OperatingMode, ParaID, Command, MultiAddress, Ticket, Costs} from "./Types.sol"; import {IGateway} from "./interfaces/IGateway.sol"; import {IInitializable} from "./interfaces/IInitializable.sol"; import {ERC1967} from "./utils/ERC1967.sol"; @@ -444,15 +444,14 @@ contract Gateway is IGateway, IInitializable { // Total fee for registering a token function registerTokenFee() external view returns (uint256) { - Cost memory cost = Assets.registerTokenCosts(); - return _calculateFee(cost); + Costs memory costs = Assets.registerTokenCosts(); + return _calculateFee(costs); } // Register a token on AssetHub function registerToken(address token) external payable { - (bytes memory payload, uint128 extraCosts) = Assets.registerToken(token); - - _submitOutbound(ASSET_HUB_PARA_ID, payload, extraCosts); + Ticket memory ticket = Assets.registerToken(token); + _submitOutbound(ASSET_HUB_PARA_ID, ticket); } // Total fee for sending a token @@ -461,8 +460,8 @@ contract Gateway is IGateway, IInitializable { view returns (uint256) { - Cost memory cost = Assets.sendTokenFee(ASSET_HUB_PARA_ID, destinationChain, destinationFee); - return _calculateFee(cost); + Costs memory costs = Assets.sendTokenCosts(ASSET_HUB_PARA_ID, destinationChain, destinationFee); + return _calculateFee(costs); } // Transfer ERC20 tokens to a Polkadot parachain @@ -502,8 +501,8 @@ contract Gateway is IGateway, IInitializable { return Verification.verifyCommitment(BEEFY_CLIENT, BRIDGE_HUB_PARA_ID_ENCODED, commitment, proof); } - // Convert ROC/KSM/DOT to ETH - function _convertToNative(UD60x18 exchangeRate, uint128 amount) internal pure returns (uint256) { + // Convert foreign currency to native currency (ROC/KSM/DOT -> ETH) + function _convertToNative(UD60x18 exchangeRate, uint256 amount) internal pure returns (uint256) { UD60x18 amountFP = convert(amount); UD60x18 nativeAmountFP = amountFP.mul(exchangeRate).mul(convert(DOT_TO_ETH_DECIMALS)); uint256 nativeAmount = convert(nativeAmountFP); @@ -511,9 +510,9 @@ contract Gateway is IGateway, IInitializable { } // Calculate the fee for accepting an outbound message - function _calculateFee(Cost memory cost) internal view returns (uint256) { + function _calculateFee(Costs memory costs) internal view returns (uint256) { PricingStorage.Layout storage pricing = PricingStorage.layout(); - return _convertToNative(pricing.exchangeRate, pricing.deliveryCost + cost.remote) + cost.local; + return costs.native + _convertToNative(pricing.exchangeRate, pricing.deliveryCost + costs.foreign); } // Submit an outbound message to Polkadot @@ -525,7 +524,7 @@ contract Gateway is IGateway, IInitializable { // Ensure outbound messaging is allowed _ensureOutboundMessagingEnabled(channel); - uint256 fee = _calculateFee(ticket.cost); + uint256 fee = _calculateFee(ticket.costs); // Ensure the user has enough funds for this message to be accepted if (msg.value < fee) { diff --git a/contracts/src/Types.sol b/contracts/src/Types.sol index bb32639ed5..e4812624bc 100644 --- a/contracts/src/Types.sol +++ b/contracts/src/Types.sol @@ -88,23 +88,15 @@ enum Command { enum AgentExecuteCommand {TransferToken} -using {total} for Fee global; - -struct Fee { - uint256 bridge; - uint256 xcm; -} - -function total(Fee memory fee) pure returns (uint256) { - return fee.bridge + fee.xcm; -} - -struct Cost { - uint256 remote; - uint256 local; +/// @dev Application-level costs for a message +struct Costs { + /// @dev Costs in foreign currency + uint256 foreign; + /// @dev Costs in native currency + uint256 native; } struct Ticket { - Cost cost; + Costs costs; bytes payload; } diff --git a/contracts/src/interfaces/IGateway.sol b/contracts/src/interfaces/IGateway.sol index 34fb590793..5f9714e330 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.22; -import {OperatingMode, InboundMessage, ParaID, ChannelID, MultiAddress, Fee} from "../Types.sol"; +import {OperatingMode, InboundMessage, ParaID, ChannelID, MultiAddress} from "../Types.sol"; import {Verification} from "../Verification.sol"; interface IGateway { @@ -66,7 +66,7 @@ interface IGateway { event TokenSent( address indexed token, address indexed sender, - ParaID destinationChain, + ParaID indexed destinationChain, MultiAddress destinationAddress, uint128 amount ); diff --git a/contracts/test/Gateway.t.sol b/contracts/test/Gateway.t.sol index 592beef98d..97be31475b 100644 --- a/contracts/test/Gateway.t.sol +++ b/contracts/test/Gateway.t.sol @@ -10,7 +10,6 @@ import {BeefyClient} from "../src/BeefyClient.sol"; import {IGateway} from "../src/interfaces/IGateway.sol"; import {IInitializable} from "../src/interfaces/IInitializable.sol"; import {Gateway} from "../src/Gateway.sol"; -import {Fee} from "../src/Types.sol"; import {GatewayMock, GatewayV2} from "./mocks/GatewayMock.sol"; import {GatewayProxy} from "../src/GatewayProxy.sol"; diff --git a/contracts/test/mocks/GatewayUpgradeMock.sol b/contracts/test/mocks/GatewayUpgradeMock.sol index 3c77886f1f..c06b53c4c2 100644 --- a/contracts/test/mocks/GatewayUpgradeMock.sol +++ b/contracts/test/mocks/GatewayUpgradeMock.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.22; import { - Channel, InboundMessage, OperatingMode, ParaID, Command, ChannelID, MultiAddress, Fee + Channel, InboundMessage, OperatingMode, ParaID, Command, ChannelID, MultiAddress } from "../../src/Types.sol"; import {IGateway} from "../../src/interfaces/IGateway.sol"; import {IInitializable} from "../../src/interfaces/IInitializable.sol"; From d0ad0e91d47658fb61d053e5a6a1200d3d05992e Mon Sep 17 00:00:00 2001 From: ron Date: Mon, 27 Nov 2023 19:45:11 +0800 Subject: [PATCH 09/38] Fix compile error&tests --- contracts/src/Assets.sol | 1 - contracts/src/Gateway.sol | 44 ++++++++----------- contracts/src/storage/AssetsStorage.sol | 1 - contracts/test/mocks/GatewayUpgradeMock.sol | 4 +- parachain/Cargo.lock | 2 +- parachain/pallets/control/src/benchmarking.rs | 6 +-- parachain/pallets/control/src/lib.rs | 14 +++--- parachain/pallets/control/src/mock.rs | 2 + parachain/pallets/outbound-queue/src/lib.rs | 24 +++++----- parachain/pallets/outbound-queue/src/types.rs | 2 +- polkadot-sdk | 2 +- 11 files changed, 45 insertions(+), 57 deletions(-) diff --git a/contracts/src/Assets.sol b/contracts/src/Assets.sol index 28e402d5fa..d62a1be719 100644 --- a/contracts/src/Assets.sol +++ b/contracts/src/Assets.sol @@ -110,7 +110,6 @@ library Assets { emit IGateway.TokenSent(sender, token, destinationChain, destinationAddress, amount); } - function registerTokenCosts() external view returns (Costs memory costs) { return _registerTokenCosts(); } diff --git a/contracts/src/Gateway.sol b/contracts/src/Gateway.sol index 8b3e45cece..ac075519ed 100644 --- a/contracts/src/Gateway.sol +++ b/contracts/src/Gateway.sol @@ -8,7 +8,17 @@ import {Verification} from "./Verification.sol"; import {Assets} from "./Assets.sol"; import {AgentExecutor} from "./AgentExecutor.sol"; import {Agent} from "./Agent.sol"; -import {Channel, ChannelID, InboundMessage, OperatingMode, ParaID, Command, MultiAddress, Ticket, Costs} from "./Types.sol"; +import { + Channel, + ChannelID, + InboundMessage, + OperatingMode, + ParaID, + Command, + MultiAddress, + Ticket, + Costs +} from "./Types.sol"; import {IGateway} from "./interfaces/IGateway.sol"; import {IInitializable} from "./interfaces/IInitializable.sol"; import {ERC1967} from "./utils/ERC1967.sol"; @@ -455,11 +465,7 @@ contract Gateway is IGateway, IInitializable { } // Total fee for sending a token - function sendTokenFee(address, ParaID destinationChain, uint128 destinationFee) - external - view - returns (uint256) - { + function sendTokenFee(address, ParaID destinationChain, uint128 destinationFee) external view returns (uint256) { Costs memory costs = Assets.sendTokenCosts(ASSET_HUB_PARA_ID, destinationChain, destinationFee); return _calculateFee(costs); } @@ -626,32 +632,20 @@ contract Gateway is IGateway, IInitializable { core.agents[BRIDGE_HUB_AGENT_ID] = bridgeHubAgent; // Initialize channel for primary governance track - core.channels[PRIMARY_GOVERNANCE_CHANNEL_ID] = Channel({ - mode: OperatingMode.Normal, - agent: bridgeHubAgent, - inboundNonce: 0, - outboundNonce: 0 - }); + core.channels[PRIMARY_GOVERNANCE_CHANNEL_ID] = + Channel({mode: OperatingMode.Normal, agent: bridgeHubAgent, inboundNonce: 0, outboundNonce: 0}); // Initialize channel for secondary governance track - core.channels[SECONDARY_GOVERNANCE_CHANNEL_ID] = Channel({ - mode: OperatingMode.Normal, - agent: bridgeHubAgent, - inboundNonce: 0, - outboundNonce: 0 - }); + core.channels[SECONDARY_GOVERNANCE_CHANNEL_ID] = + Channel({mode: OperatingMode.Normal, agent: bridgeHubAgent, inboundNonce: 0, outboundNonce: 0}); // Initialize agent for for AssetHub address assetHubAgent = address(new Agent(ASSET_HUB_AGENT_ID)); core.agents[ASSET_HUB_AGENT_ID] = assetHubAgent; // Initialize channel for AssetHub - core.channels[ASSET_HUB_PARA_ID.into()] = Channel({ - mode: OperatingMode.Normal, - agent: assetHubAgent, - inboundNonce: 0, - outboundNonce: 0 - }); + core.channels[ASSET_HUB_PARA_ID.into()] = + Channel({mode: OperatingMode.Normal, agent: assetHubAgent, inboundNonce: 0, outboundNonce: 0}); // Initialize pricing storage PricingStorage.Layout storage pricing = PricingStorage.layout(); @@ -662,6 +656,6 @@ contract Gateway is IGateway, IInitializable { AssetsStorage.Layout storage assets = AssetsStorage.layout(); assets.registerTokenFee = config.registerTokenFee; assets.assetHubAssetCreationFee = config.assetHubAssetCreationFee; - assets.assetHubReserveTransferFee = config.assetHubReserveTransferFee; + assets.assetHubReserveTransferFee = config.assetHubReserveTransferFee; } } diff --git a/contracts/src/storage/AssetsStorage.sol b/contracts/src/storage/AssetsStorage.sol index dbea7484b2..238e90f1cb 100644 --- a/contracts/src/storage/AssetsStorage.sol +++ b/contracts/src/storage/AssetsStorage.sol @@ -10,7 +10,6 @@ library AssetsStorage { uint128 assetHubReserveTransferFee; // Extra fee for registering a token, to discourage spamming (Ether) uint256 registerTokenFee; - } bytes32 internal constant SLOT = keccak256("org.snowbridge.storage.assets"); diff --git a/contracts/test/mocks/GatewayUpgradeMock.sol b/contracts/test/mocks/GatewayUpgradeMock.sol index c06b53c4c2..87bd6884e1 100644 --- a/contracts/test/mocks/GatewayUpgradeMock.sol +++ b/contracts/test/mocks/GatewayUpgradeMock.sol @@ -2,9 +2,7 @@ // SPDX-FileCopyrightText: 2023 Snowfork pragma solidity 0.8.22; -import { - Channel, InboundMessage, OperatingMode, ParaID, Command, ChannelID, MultiAddress -} from "../../src/Types.sol"; +import {Channel, InboundMessage, OperatingMode, ParaID, Command, ChannelID, MultiAddress} from "../../src/Types.sol"; import {IGateway} from "../../src/interfaces/IGateway.sol"; import {IInitializable} from "../../src/interfaces/IInitializable.sol"; import {Verification} from "../../src/Verification.sol"; diff --git a/parachain/Cargo.lock b/parachain/Cargo.lock index fdb8346791..f16e80b990 100644 --- a/parachain/Cargo.lock +++ b/parachain/Cargo.lock @@ -1526,7 +1526,7 @@ dependencies = [ [[package]] name = "ethabi-decode" version = "1.3.3" -source = "git+https://github.com/snowfork/ethabi-decode.git?branch=master#6f63405bb33ef4365a1c62b72d499fa0f448118e" +source = "git+https://github.com/Snowfork/ethabi-decode.git?branch=master#6f63405bb33ef4365a1c62b72d499fa0f448118e" dependencies = [ "ethereum-types", "tiny-keccak 1.5.0", diff --git a/parachain/pallets/control/src/benchmarking.rs b/parachain/pallets/control/src/benchmarking.rs index fa850f5713..394b66c3d9 100644 --- a/parachain/pallets/control/src/benchmarking.rs +++ b/parachain/pallets/control/src/benchmarking.rs @@ -64,7 +64,7 @@ mod benchmarks { SnowbridgeControl::::create_agent(origin.clone())?; #[extrinsic_call] - _(origin as T::RuntimeOrigin, OperatingMode::Normal, 1); + _(origin as T::RuntimeOrigin, OperatingMode::Normal); Ok(()) } @@ -76,7 +76,7 @@ mod benchmarks { let origin = T::Helper::make_xcm_origin(origin_location); fund_sovereign_account::(origin_para_id.into())?; SnowbridgeControl::::create_agent(origin.clone())?; - SnowbridgeControl::::create_channel(origin.clone(), OperatingMode::Normal, 1)?; + SnowbridgeControl::::create_channel(origin.clone(), OperatingMode::Normal)?; #[extrinsic_call] _(origin as T::RuntimeOrigin, OperatingMode::RejectingOutboundMessages, 1); @@ -93,7 +93,7 @@ mod benchmarks { fund_sovereign_account::(origin_para_id.into())?; SnowbridgeControl::::create_agent(origin.clone())?; - SnowbridgeControl::::create_channel(origin.clone(), OperatingMode::Normal, 1)?; + SnowbridgeControl::::create_channel(origin.clone(), OperatingMode::Normal)?; #[extrinsic_call] _(RawOrigin::Root, channel_id, OperatingMode::RejectingOutboundMessages, 1); diff --git a/parachain/pallets/control/src/lib.rs b/parachain/pallets/control/src/lib.rs index 7a82c6e90d..418b1f94d2 100644 --- a/parachain/pallets/control/src/lib.rs +++ b/parachain/pallets/control/src/lib.rs @@ -55,8 +55,8 @@ pub use weights::*; use frame_support::{ pallet_prelude::*, traits::{ - fungible::Mutate, - tokens::{Balance, Preservation}, + fungible::{Inspect, Mutate}, + tokens::Preservation, EnsureOrigin, }, }; @@ -69,7 +69,7 @@ use snowbridge_core::{ }; use sp_core::{RuntimeDebug, H160, H256}; use sp_io::hashing::blake2_256; -use sp_runtime::{traits::BadOrigin, DispatchError}; +use sp_runtime::{traits::BadOrigin, DispatchError, SaturatedConversion}; use sp_std::prelude::*; use xcm::prelude::*; use xcm_executor::traits::ConvertLocation; @@ -79,7 +79,8 @@ use frame_support::traits::OriginTrait; pub use pallet::*; -pub type BalanceOf = ::Balance; +pub type BalanceOf = + <::Token as Inspect<::AccountId>>::Balance; pub type AccountIdOf = ::AccountId; pub type PricingParametersOf = PricingParametersRecord>; @@ -146,8 +147,6 @@ pub mod pallet { /// Converts MultiLocation to AgentId type AgentIdOf: ConvertLocation; - type Balance: Balance + Into; - /// Token reserved for control operations type Token: Mutate; @@ -159,6 +158,7 @@ pub mod pallet { type DefaultPricingParameters: Get>; /// Cost of delivering a message from Ethereum + /// Todo: Remove with a dynamic read from inbound queue type InboundDeliveryCost: Get>; type WeightInfo: WeightInfo; @@ -347,7 +347,7 @@ pub mod pallet { let command = Command::SetPricingParameters { exchange_rate: params.exchange_rate.into(), - delivery_cost: T::InboundDeliveryCost::get().into(), + delivery_cost: T::InboundDeliveryCost::get().saturated_into::(), }; Self::send(PRIMARY_GOVERNANCE_CHANNEL, command, PaysFee::::No)?; diff --git a/parachain/pallets/control/src/mock.rs b/parachain/pallets/control/src/mock.rs index 5668bde7cd..ec9f98fff5 100644 --- a/parachain/pallets/control/src/mock.rs +++ b/parachain/pallets/control/src/mock.rs @@ -204,6 +204,7 @@ parameter_types! { fee_per_gas: gwei(20), rewards: Rewards { local: 1 * DOT, remote: meth(1) } }; + pub const InboundDeliveryCost: u128 = 1_000_000_000; } @@ -223,6 +224,7 @@ impl crate::Config for Test { type Token = Balances; type DefaultPricingParameters = Parameters; type WeightInfo = (); + type InboundDeliveryCost = InboundDeliveryCost; #[cfg(feature = "runtime-benchmarks")] type Helper = (); } diff --git a/parachain/pallets/outbound-queue/src/lib.rs b/parachain/pallets/outbound-queue/src/lib.rs index 6bdbdb87b2..ff179e6176 100644 --- a/parachain/pallets/outbound-queue/src/lib.rs +++ b/parachain/pallets/outbound-queue/src/lib.rs @@ -13,21 +13,18 @@ //! The message submission pipeline works like this: //! 1. The message is first validated via the implementation for //! [`snowbridge_core::outbound::SendMessage::validate`] -//! 2. The message is then enqueued for later processing via the implementation -//! for [`snowbridge_core::outbound::SendMessage::deliver`] +//! 2. The message is then enqueued for later processing via the implementation for +//! [`snowbridge_core::outbound::SendMessage::deliver`] //! 3. The underlying message queue is implemented by [`Config::MessageQueue`] -//! 4. The message queue delivers messages back to this pallet via -//! the implementation for [`frame_support::traits::ProcessMessage::process_message`] -//! 5. The message is processed in `Pallet::do_process_message`: -//! a. Assigned a nonce -//! b. ABI-encoded, hashed, and stored in the `MessageLeaves` vector -//! 6. At the end of the block, a merkle root is constructed from all the -//! leaves in `MessageLeaves`. +//! 4. The message queue delivers messages back to this pallet via the implementation for +//! [`frame_support::traits::ProcessMessage::process_message`] +//! 5. The message is processed in `Pallet::do_process_message`: a. Assigned a nonce b. ABI-encoded, +//! hashed, and stored in the `MessageLeaves` vector +//! 6. At the end of the block, a merkle root is constructed from all the leaves in `MessageLeaves`. //! 7. This merkle root is inserted into the parachain header as a digest item -//! 8. Offchain relayers are able to relay the message to Ethereum after: -//! a. Generating a merkle proof for the committed message using the `prove_message` -//! runtime API -//! b. Reading the actual message content from the `Messages` vector in storage +//! 8. Offchain relayers are able to relay the message to Ethereum after: a. Generating a merkle +//! proof for the committed message using the `prove_message` runtime API b. Reading the actual +//! message content from the `Messages` vector in storage //! //! On the Ethereum side, the message root is ultimately the thing being //! verified by the Polkadot light client. @@ -103,7 +100,6 @@ use frame_support::{ weights::{Weight, WeightToFee}, }; use snowbridge_core::{ - gwei, meth, outbound::{Command, Fee, GasMeter, QueuedMessage, VersionedQueuedMessage, ETHER_DECIMALS}, BasicOperatingMode, ChannelId, }; diff --git a/parachain/pallets/outbound-queue/src/types.rs b/parachain/pallets/outbound-queue/src/types.rs index 1b2b3aeaea..82ed3fb4b9 100644 --- a/parachain/pallets/outbound-queue/src/types.rs +++ b/parachain/pallets/outbound-queue/src/types.rs @@ -4,7 +4,7 @@ use frame_support::traits::ProcessMessage; use scale_info::TypeInfo; use serde::{Deserialize, Serialize}; use sp_arithmetic::FixedU128; -use sp_core::{H256, U256}; +use sp_core::H256; use sp_runtime::{traits::Zero, RuntimeDebug}; use sp_std::prelude::*; diff --git a/polkadot-sdk b/polkadot-sdk index 52bcb07b16..22506915c8 160000 --- a/polkadot-sdk +++ b/polkadot-sdk @@ -1 +1 @@ -Subproject commit 52bcb07b166fa12b1a1446fb655d3ae42fe84170 +Subproject commit 22506915c831174198e2358f81741eff58ac03fc From 5df3d942c55da3456950430843c2a8354799aeb4 Mon Sep 17 00:00:00 2001 From: Vincent Geddes Date: Mon, 27 Nov 2023 15:32:16 +0200 Subject: [PATCH 10/38] remove obsolete code --- contracts/src/Gateway.sol | 5 ----- 1 file changed, 5 deletions(-) diff --git a/contracts/src/Gateway.sol b/contracts/src/Gateway.sol index ac075519ed..673daf5930 100644 --- a/contracts/src/Gateway.sol +++ b/contracts/src/Gateway.sol @@ -336,11 +336,6 @@ contract Gateway is IGateway, IInitializable { ChannelID channelID; /// @dev The new operating mode OperatingMode mode; - /// @dev The new fee in DOT for accepting outbound messages - uint128 fee; - /// @dev The new ETH/DOT exchange rate - uint128 exchangeRateNumerator; - uint128 exchangeRateDenominator; } /// @dev Update the configuration for a channel From 510880c717bf34941c75aff2ed4c63b272964fa3 Mon Sep 17 00:00:00 2001 From: Vincent Geddes Date: Mon, 27 Nov 2023 15:34:58 +0200 Subject: [PATCH 11/38] fix --- contracts/src/Assets.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/src/Assets.sol b/contracts/src/Assets.sol index d62a1be719..6a490169c6 100644 --- a/contracts/src/Assets.sol +++ b/contracts/src/Assets.sol @@ -73,7 +73,7 @@ library Assets { AssetsStorage.Layout storage $ = AssetsStorage.layout(); _transferToAgent(assetHubAgent, token, sender, amount); - ticket.cost = _sendTokenCosts(assetHubParaID, destinationChain, destinationChainFee); + ticket.costs = _sendTokenCosts(assetHubParaID, destinationChain, destinationChainFee); if (destinationChain == assetHubParaID) { if (destinationAddress.isAddress32()) { @@ -129,7 +129,7 @@ library Assets { revert InvalidToken(); } - ticket.cost = _registerTokenCosts(); + ticket.costs = _registerTokenCosts(); ticket.payload = SubstrateTypes.RegisterToken(token); emit IGateway.TokenRegistrationSent(token); From 5e88fd40a4fe097136f399789363d2be51e2ffdc Mon Sep 17 00:00:00 2001 From: ron Date: Mon, 27 Nov 2023 21:59:48 +0800 Subject: [PATCH 12/38] Fix contract tests --- contracts/src/Assets.sol | 6 +- contracts/src/DeployScript.sol | 3 +- contracts/src/Gateway.sol | 7 +- contracts/test/Gateway.t.sol | 101 +++++++++++---------------- contracts/test/mocks/GatewayMock.sol | 4 -- 5 files changed, 49 insertions(+), 72 deletions(-) diff --git a/contracts/src/Assets.sol b/contracts/src/Assets.sol index d62a1be719..c4b0785b33 100644 --- a/contracts/src/Assets.sol +++ b/contracts/src/Assets.sol @@ -73,7 +73,7 @@ library Assets { AssetsStorage.Layout storage $ = AssetsStorage.layout(); _transferToAgent(assetHubAgent, token, sender, amount); - ticket.cost = _sendTokenCosts(assetHubParaID, destinationChain, destinationChainFee); + ticket.costs = _sendTokenCosts(assetHubParaID, destinationChain, destinationChainFee); if (destinationChain == assetHubParaID) { if (destinationAddress.isAddress32()) { @@ -123,13 +123,11 @@ library Assets { /// @dev Enqueues a create native token message to substrate. /// @param token The ERC20 token address. function registerToken(address token) external returns (Ticket memory ticket) { - AssetsStorage.Layout storage $ = AssetsStorage.layout(); - if (!token.isContract()) { revert InvalidToken(); } - ticket.cost = _registerTokenCosts(); + ticket.costs = _registerTokenCosts(); ticket.payload = SubstrateTypes.RegisterToken(token); emit IGateway.TokenRegistrationSent(token); diff --git a/contracts/src/DeployScript.sol b/contracts/src/DeployScript.sol index 92443dfcdc..e297db8d5a 100644 --- a/contracts/src/DeployScript.sol +++ b/contracts/src/DeployScript.sol @@ -84,7 +84,8 @@ contract DeployScript is Script { mode: defaultOperatingMode, deliveryCost: uint128(vm.envUint("DEFAULT_FEE")), registerTokenFee: uint128(vm.envUint("REGISTER_NATIVE_TOKEN_FEE")), - sendTokenFee: uint128(vm.envUint("SEND_NATIVE_TOKEN_FEE")), + assetHubCreateAssetFee: uint128(vm.envUint("SEND_NATIVE_TOKEN_FEE")), + assetHubReserveTransferFee: uint128(vm.envUint("SEND_NATIVE_TOKEN_FEE")), exchangeRate: ud60x18(0.0025e18) }); diff --git a/contracts/src/Gateway.sol b/contracts/src/Gateway.sol index ac075519ed..c4074560b4 100644 --- a/contracts/src/Gateway.sol +++ b/contracts/src/Gateway.sol @@ -508,9 +508,9 @@ contract Gateway is IGateway, IInitializable { } // Convert foreign currency to native currency (ROC/KSM/DOT -> ETH) - function _convertToNative(UD60x18 exchangeRate, uint256 amount) internal pure returns (uint256) { + function _convertToNative(UD60x18 exchangeRate, uint256 amount) internal view returns (uint256) { UD60x18 amountFP = convert(amount); - UD60x18 nativeAmountFP = amountFP.mul(exchangeRate).mul(convert(DOT_TO_ETH_DECIMALS)); + UD60x18 nativeAmountFP = amountFP.mul(exchangeRate).mul(DOT_TO_ETH_DECIMALS); uint256 nativeAmount = convert(nativeAmountFP); return nativeAmount; } @@ -525,7 +525,6 @@ contract Gateway is IGateway, IInitializable { function _submitOutbound(ParaID dest, Ticket memory ticket) internal { ChannelID channelID = dest.into(); Channel storage channel = _ensureChannel(channelID); - PricingStorage.Layout storage pricing = PricingStorage.layout(); // Ensure outbound messaging is allowed _ensureOutboundMessagingEnabled(channel); @@ -655,7 +654,7 @@ contract Gateway is IGateway, IInitializable { // Initialize assets storage AssetsStorage.Layout storage assets = AssetsStorage.layout(); assets.registerTokenFee = config.registerTokenFee; - assets.assetHubAssetCreationFee = config.assetHubAssetCreationFee; + assets.assetHubCreateAssetFee = config.assetHubCreateAssetFee; assets.assetHubReserveTransferFee = config.assetHubReserveTransferFee; } } diff --git a/contracts/test/Gateway.t.sol b/contracts/test/Gateway.t.sol index 97be31475b..1ef58fe9bd 100644 --- a/contracts/test/Gateway.t.sol +++ b/contracts/test/Gateway.t.sol @@ -21,6 +21,7 @@ import {Assets} from "../src/Assets.sol"; import {SubstrateTypes} from "./../src/SubstrateTypes.sol"; import {NativeTransferFailed} from "../src/utils/SafeTransfer.sol"; +import {PricingStorage} from "../src/storage/PricingStorage.sol"; import { AgentExecuteCommand, @@ -90,15 +91,17 @@ contract GatewayTest is Test { assetHubAgentID, dotToEthDecimals ); + Gateway.Config memory config = Gateway.Config({ + mode: OperatingMode.Normal, + deliveryCost: outboundFee, + registerTokenFee: registerTokenFee, + assetHubCreateAssetFee: registerTokenFee, + assetHubReserveTransferFee: sendTokenFee, + exchangeRate: exchangeRate + }); gateway = new GatewayProxy( address(gatewayLogic), - abi.encode( - OperatingMode.Normal, - outboundFee, - registerTokenFee, - sendTokenFee, - exchangeRate - ) + abi.encode(config) ); GatewayMock(address(gateway)).setCommitmentsAreVerified(true); @@ -288,16 +291,14 @@ contract GatewayTest is Test { address user = makeAddr("user"); deal(address(token), user, 1); - Fee memory fee = IGateway(address(gateway)).sendTokenFee(address(token), ParaID.wrap(0), 1); + uint256 fee = IGateway(address(gateway)).sendTokenFee(address(token), ParaID.wrap(0), 1); // Let gateway lock up to 1 tokens hoax(user); token.approve(address(gateway), 1); - hoax(user, fee.total()); - IGateway(address(gateway)).sendToken{value: fee.total()}( - address(token), ParaID.wrap(0), recipientAddress32, 1, 1 - ); + hoax(user, fee); + IGateway(address(gateway)).sendToken{value: fee}(address(token), ParaID.wrap(0), recipientAddress32, 1, 1); assertEq(user.balance, 0); } @@ -380,12 +381,8 @@ contract GatewayTest is Test { GatewayMock(address(gateway)).createAgentPublic(abi.encode(Gateway.CreateAgentParams({agentID: agentID}))); - Gateway.CreateChannelParams memory params = Gateway.CreateChannelParams({ - channelID: paraID.into(), - agentID: agentID, - mode: OperatingMode.Normal, - outboundFee: outboundFee - }); + Gateway.CreateChannelParams memory params = + Gateway.CreateChannelParams({channelID: paraID.into(), agentID: agentID, mode: OperatingMode.Normal}); vm.expectEmit(true, false, false, true); emit IGateway.ChannelCreated(paraID.into()); @@ -396,12 +393,8 @@ contract GatewayTest is Test { ParaID paraID = ParaID.wrap(3042); bytes32 agentID = keccak256("3042"); - Gateway.CreateChannelParams memory params = Gateway.CreateChannelParams({ - channelID: paraID.into(), - mode: OperatingMode.Normal, - agentID: agentID, - outboundFee: 1 ether - }); + Gateway.CreateChannelParams memory params = + Gateway.CreateChannelParams({channelID: paraID.into(), mode: OperatingMode.Normal, agentID: agentID}); vm.expectRevert(Gateway.AgentDoesNotExist.selector); GatewayMock(address(gateway)).createChannelPublic(abi.encode(params)); @@ -413,12 +406,8 @@ contract GatewayTest is Test { GatewayMock(address(gateway)).createAgentPublic(abi.encode(Gateway.CreateAgentParams({agentID: agentID}))); - Gateway.CreateChannelParams memory params = Gateway.CreateChannelParams({ - channelID: paraID.into(), - agentID: agentID, - mode: OperatingMode.Normal, - outboundFee: 1 ether - }); + Gateway.CreateChannelParams memory params = + Gateway.CreateChannelParams({channelID: paraID.into(), agentID: agentID, mode: OperatingMode.Normal}); GatewayMock(address(gateway)).createChannelPublic(abi.encode(params)); @@ -428,7 +417,8 @@ contract GatewayTest is Test { function testUpdateChannel() public { // get current fee (0.0025 ether) - uint256 fee = IGateway(address(gateway)).channelFeeOf(assetHubParaID.into()); + PricingStorage.Layout storage pricing = PricingStorage.layout(); + uint256 fee = pricing.deliveryCost; bytes memory params = abi.encode( Gateway.UpdateChannelParams({ @@ -445,7 +435,7 @@ contract GatewayTest is Test { GatewayMock(address(gateway)).updateChannelPublic(params); // Due to the new exchange rate, new fee is halved - uint256 newFee = IGateway(address(gateway)).channelFeeOf(assetHubParaID.into()); + uint256 newFee = pricing.deliveryCost; assertEq(fee / 2, newFee); } @@ -591,8 +581,7 @@ contract GatewayTest is Test { vm.expectEmit(true, false, false, false); emit IGateway.OutboundMessageAccepted(assetHubParaID.into(), 1, messageID, bytes("")); - uint256 totalFee = - GatewayMock(address(gateway)).calculateLocalFeePublic(exchangeRate, outboundFee + registerTokenFee); + uint256 totalFee = GatewayMock(address(gateway)).registerTokenFee(); uint256 balanceBefore = address(this).balance; IGateway(address(gateway)).registerToken{value: totalFee + 1 ether}(address(token)); @@ -611,7 +600,7 @@ contract GatewayTest is Test { // Multilocation for recipient ParaID destPara = ParaID.wrap(2043); - Fee memory fee = IGateway(address(gateway)).sendTokenFee(address(token), destPara, 1); + uint256 fee = IGateway(address(gateway)).sendTokenFee(address(token), destPara, 1); vm.expectEmit(true, true, false, true); emit IGateway.TokenSent(address(this), address(token), destPara, recipientAddress32, 1); @@ -620,7 +609,7 @@ contract GatewayTest is Test { vm.expectEmit(true, false, false, false); emit IGateway.OutboundMessageAccepted(assetHubParaID.into(), 1, messageID, bytes("")); - IGateway(address(gateway)).sendToken{value: fee.total()}(address(token), destPara, recipientAddress32, 1, 1); + IGateway(address(gateway)).sendToken{value: fee}(address(token), destPara, recipientAddress32, 1, 1); } function testSendTokenAddress32ToAssetHub() public { @@ -630,7 +619,7 @@ contract GatewayTest is Test { // Multilocation for recipient ParaID destPara = assetHubParaID; - Fee memory fee = IGateway(address(gateway)).sendTokenFee(address(token), destPara, 1); + uint256 fee = IGateway(address(gateway)).sendTokenFee(address(token), destPara, 1); vm.expectEmit(true, true, false, true); emit IGateway.TokenSent(address(this), address(token), destPara, recipientAddress32, 1); @@ -639,7 +628,7 @@ contract GatewayTest is Test { vm.expectEmit(true, false, false, false); emit IGateway.OutboundMessageAccepted(assetHubParaID.into(), 1, messageID, bytes("")); - IGateway(address(gateway)).sendToken{value: fee.total()}(address(token), destPara, recipientAddress32, 1, 1); + IGateway(address(gateway)).sendToken{value: fee}(address(token), destPara, recipientAddress32, 1, 1); } function testSendTokenAddress20() public { @@ -649,7 +638,7 @@ contract GatewayTest is Test { // Multilocation for recipient ParaID destPara = ParaID.wrap(2043); - Fee memory fee = IGateway(address(gateway)).sendTokenFee(address(token), destPara, 1); + uint256 fee = IGateway(address(gateway)).sendTokenFee(address(token), destPara, 1); vm.expectEmit(true, true, false, true); emit IGateway.TokenSent(address(this), address(token), destPara, recipientAddress20, 1); @@ -658,7 +647,7 @@ contract GatewayTest is Test { vm.expectEmit(true, false, false, false); emit IGateway.OutboundMessageAccepted(assetHubParaID.into(), 1, messageID, bytes("")); - IGateway(address(gateway)).sendToken{value: fee.total()}(address(token), destPara, recipientAddress20, 1, 1); + IGateway(address(gateway)).sendToken{value: fee}(address(token), destPara, recipientAddress20, 1, 1); } function testSendTokenAddress20FailsInvalidDestination() public { @@ -765,8 +754,9 @@ contract GatewayTest is Test { OperatingMode channelMode = gw.channelOperatingModeOf(assetHubParaID.into()); assertEq(uint256(channelMode), 0); - uint256 fee = gw.channelFeeOf(assetHubParaID.into()); - assertEq(fee, 0.0025 ether); + PricingStorage.Layout storage pricing = PricingStorage.layout(); + uint256 fee = pricing.deliveryCost; + assertEq(fee, 0); (uint64 inbound, uint64 outbound) = gw.channelNoncesOf(assetHubParaID.into()); assertEq(inbound, 0); @@ -797,28 +787,21 @@ contract GatewayTest is Test { ); } - function testCalculateLocalFee() public { - // 400 DOT = 1 ETH - uint256 remoteFee = 400e10; - uint256 localFee = GatewayMock(address(gateway)).calculateLocalFeePublic(exchangeRate, remoteFee); - assertEq(localFee, 1 ether); - - // 1 DOT = 0.0025 ETH - remoteFee = 1e10; - localFee = GatewayMock(address(gateway)).calculateLocalFeePublic(exchangeRate, remoteFee); - assertEq(localFee, 0.0025 ether); - } - function testSetTokenFees() public { // Double the fees - - Fee memory fee = IGateway(address(gateway)).registerTokenFee(); - assertEq(fee.xcm, 0.0025 ether); + uint256 fee = IGateway(address(gateway)).registerTokenFee(); + assertEq(fee, 5000010000000000); GatewayMock(address(gateway)).setTokenTransferFeesPublic( - abi.encode(Gateway.SetTokenTransferFeesParams({register: registerTokenFee * 2, send: sendTokenFee * 2})) + abi.encode( + Gateway.SetTokenTransferFeesParams({ + assetHubCreateAssetFee: registerTokenFee, + registerTokenFee: registerTokenFee * 2, + assetHubReserveTransferFee: sendTokenFee * 2 + }) + ) ); fee = IGateway(address(gateway)).registerTokenFee(); - assertEq(fee.xcm, 0.005e18); + assertEq(fee, 5000020000000000); } bytes32 public expectChannelIDBytes = bytes32(0xc173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539); diff --git a/contracts/test/mocks/GatewayMock.sol b/contracts/test/mocks/GatewayMock.sol index 287769b5a3..6146dc058b 100644 --- a/contracts/test/mocks/GatewayMock.sol +++ b/contracts/test/mocks/GatewayMock.sol @@ -80,10 +80,6 @@ contract GatewayMock is Gateway { function setTokenTransferFeesPublic(bytes calldata params) external { this.setTokenTransferFees(params); } - - function calculateLocalFeePublic(UD60x18 exchangeRate, uint256 remoteFee) external pure returns (uint256) { - return calculateLocalFee(exchangeRate, remoteFee); - } } library AdditionalStorage { From 0fb8c7d46cf7d4910655496382edf283b180d4a0 Mon Sep 17 00:00:00 2001 From: ron Date: Mon, 27 Nov 2023 22:04:40 +0800 Subject: [PATCH 13/38] Test --- contracts/test/Gateway.t.sol | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/contracts/test/Gateway.t.sol b/contracts/test/Gateway.t.sol index 1ef58fe9bd..1dd4f35911 100644 --- a/contracts/test/Gateway.t.sol +++ b/contracts/test/Gateway.t.sol @@ -423,10 +423,7 @@ contract GatewayTest is Test { bytes memory params = abi.encode( Gateway.UpdateChannelParams({ channelID: assetHubParaID.into(), - mode: OperatingMode.RejectingOutboundMessages, - fee: outboundFee * 1, - exchangeRateNumerator: 1, - exchangeRateDenominator: 800 + mode: OperatingMode.RejectingOutboundMessages }) ); @@ -443,10 +440,7 @@ contract GatewayTest is Test { bytes memory params = abi.encode( Gateway.UpdateChannelParams({ channelID: ParaID.wrap(5956).into(), - mode: OperatingMode.RejectingOutboundMessages, - fee: outboundFee * 2, - exchangeRateNumerator: 1, - exchangeRateDenominator: 800 + mode: OperatingMode.RejectingOutboundMessages }) ); @@ -458,10 +452,7 @@ contract GatewayTest is Test { bytes memory params = abi.encode( Gateway.UpdateChannelParams({ channelID: ChannelID.wrap(bytes32(uint256(1))), - mode: OperatingMode.RejectingOutboundMessages, - fee: outboundFee * 2, - exchangeRateNumerator: 1, - exchangeRateDenominator: 800 + mode: OperatingMode.RejectingOutboundMessages }) ); @@ -688,10 +679,7 @@ contract GatewayTest is Test { bytes memory params = abi.encode( Gateway.UpdateChannelParams({ channelID: assetHubParaID.into(), - mode: OperatingMode.RejectingOutboundMessages, - fee: outboundFee * 2, - exchangeRateNumerator: 1, - exchangeRateDenominator: 800 + mode: OperatingMode.RejectingOutboundMessages }) ); GatewayMock(address(gateway)).updateChannelPublic(params); From 7f403d7bc53caba0bd4fca69ad9e4440ae34077d Mon Sep 17 00:00:00 2001 From: ron Date: Tue, 28 Nov 2023 08:08:20 +0800 Subject: [PATCH 14/38] SetPricingParameters --- contracts/src/Gateway.sol | 28 ++++++++++++++- contracts/src/Types.sol | 3 +- contracts/src/interfaces/IGateway.sol | 7 ++++ contracts/test/Gateway.t.sol | 39 +++++++++++++++------ contracts/test/mocks/GatewayMock.sol | 4 +++ contracts/test/mocks/GatewayUpgradeMock.sol | 5 +++ 6 files changed, 74 insertions(+), 12 deletions(-) diff --git a/contracts/src/Gateway.sol b/contracts/src/Gateway.sol index db6b01be79..32c5ac5ab8 100644 --- a/contracts/src/Gateway.sol +++ b/contracts/src/Gateway.sol @@ -199,6 +199,11 @@ contract Gateway is IGateway, IInitializable { catch { success = false; } + } else if (message.command == Command.SetPricingParameters) { + try Gateway(this).setPricingParameters{gas: maxDispatchGas}(message.params) {} + catch { + success = false; + } } // Calculate the actual cost of executing this message @@ -433,7 +438,7 @@ contract Gateway is IGateway, IInitializable { uint128 registerTokenFee; } - // @dev Set the operating mode of the gateway + // @dev Set token fees of the gateway function setTokenTransferFees(bytes calldata data) external onlySelf { AssetsStorage.Layout storage $ = AssetsStorage.layout(); SetTokenTransferFeesParams memory params = abi.decode(data, (SetTokenTransferFeesParams)); @@ -443,6 +448,27 @@ contract Gateway is IGateway, IInitializable { emit TokenTransferFeesChanged(); } + struct SetPricingParametersParams { + /// @dev The ETH/DOT exchange rate + UD60x18 exchangeRate; + /// @dev The cost of delivering messages to BridgeHub in DOT + uint128 deliveryCost; + } + + // @dev Set pricing params of the gateway + function setPricingParameters(bytes calldata data) external onlySelf { + PricingStorage.Layout storage pricing = PricingStorage.layout(); + SetPricingParametersParams memory params = abi.decode(data, (SetPricingParametersParams)); + pricing.exchangeRate = params.exchangeRate; + pricing.deliveryCost = params.deliveryCost; + emit PricingParametersChanged(); + } + + function getPricingParameters() external view returns (UD60x18, uint128) { + PricingStorage.Layout storage pricing = PricingStorage.layout(); + return (pricing.exchangeRate, pricing.deliveryCost); + } + /** * Assets */ diff --git a/contracts/src/Types.sol b/contracts/src/Types.sol index e4812624bc..8180f7fa85 100644 --- a/contracts/src/Types.sol +++ b/contracts/src/Types.sol @@ -83,7 +83,8 @@ enum Command { UpdateChannel, SetOperatingMode, TransferNativeFromAgent, - SetTokenTransferFees + SetTokenTransferFees, + SetPricingParameters } enum AgentExecuteCommand {TransferToken} diff --git a/contracts/src/interfaces/IGateway.sol b/contracts/src/interfaces/IGateway.sol index 5f9714e330..56b89b4f25 100644 --- a/contracts/src/interfaces/IGateway.sol +++ b/contracts/src/interfaces/IGateway.sol @@ -4,6 +4,7 @@ pragma solidity 0.8.22; import {OperatingMode, InboundMessage, ParaID, ChannelID, MultiAddress} from "../Types.sol"; import {Verification} from "../Verification.sol"; +import {UD60x18} from "prb/math/src/UD60x18.sol"; interface IGateway { /** @@ -74,6 +75,9 @@ interface IGateway { /// @dev Emitted when a command is sent to register a new wrapped token on AssetHub event TokenRegistrationSent(address token); + // @dev Emitted when pricing params updated + event PricingParametersChanged(); + /// @dev Fee schedule in Ether for registering a token, covering /// 1. Delivery costs to BridgeHub /// 2. XCM Execution costs on AssetHub @@ -99,4 +103,7 @@ interface IGateway { uint128 destinationFee, uint128 amount ) external payable; + + /// @dev Get pricing params (exchangeRate,deliveryCost) + function getPricingParameters() external view returns (UD60x18, uint128); } diff --git a/contracts/test/Gateway.t.sol b/contracts/test/Gateway.t.sol index 1dd4f35911..289460a8f5 100644 --- a/contracts/test/Gateway.t.sol +++ b/contracts/test/Gateway.t.sol @@ -66,8 +66,9 @@ contract GatewayTest is Test { // remote fees in DOT uint128 public outboundFee = 1e10; - uint128 public registerTokenFee = 1e10; + uint128 public registerTokenFee = 0; uint128 public sendTokenFee = 1e10; + uint128 public createTokenFee = 1e10; MultiAddress public recipientAddress32; MultiAddress public recipientAddress20; @@ -95,7 +96,7 @@ contract GatewayTest is Test { mode: OperatingMode.Normal, deliveryCost: outboundFee, registerTokenFee: registerTokenFee, - assetHubCreateAssetFee: registerTokenFee, + assetHubCreateAssetFee: createTokenFee, assetHubReserveTransferFee: sendTokenFee, exchangeRate: exchangeRate }); @@ -743,8 +744,9 @@ contract GatewayTest is Test { assertEq(uint256(channelMode), 0); PricingStorage.Layout storage pricing = PricingStorage.layout(); - uint256 fee = pricing.deliveryCost; - assertEq(fee, 0); + + (UD60x18 _exchangeRate, uint128 fee) = gw.getPricingParameters(); + assertEq(fee, 10000000000); (uint64 inbound, uint64 outbound) = gw.channelNoncesOf(assetHubParaID.into()); assertEq(inbound, 0); @@ -776,20 +778,21 @@ contract GatewayTest is Test { } function testSetTokenFees() public { - // Double the fees uint256 fee = IGateway(address(gateway)).registerTokenFee(); - assertEq(fee, 5000010000000000); + assertEq(fee, 5000000000000000); + // Double the assetHubCreateAssetFee GatewayMock(address(gateway)).setTokenTransferFeesPublic( abi.encode( Gateway.SetTokenTransferFeesParams({ - assetHubCreateAssetFee: registerTokenFee, - registerTokenFee: registerTokenFee * 2, - assetHubReserveTransferFee: sendTokenFee * 2 + assetHubCreateAssetFee: createTokenFee * 2, + registerTokenFee: registerTokenFee, + assetHubReserveTransferFee: sendTokenFee }) ) ); fee = IGateway(address(gateway)).registerTokenFee(); - assertEq(fee, 5000020000000000); + // since deliveryCost not changed, so the total fee increased only by 50% + assertEq(fee, 7500000000000000); } bytes32 public expectChannelIDBytes = bytes32(0xc173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539); @@ -799,4 +802,20 @@ contract GatewayTest is Test { ChannelID channel_id = para_id.into(); assertEq(ChannelID.unwrap(channel_id), expectChannelIDBytes); } + + function testSetPricingParameters() public { + uint256 fee = IGateway(address(gateway)).registerTokenFee(); + assertEq(fee, 5000000000000000); + // Double the exchangeRate + GatewayMock(address(gateway)).setPricingParametersPublic( + abi.encode( + Gateway.SetPricingParametersParams({ + exchangeRate: exchangeRate.mul(convert(2)), + deliveryCost: outboundFee + }) + ) + ); + fee = IGateway(address(gateway)).registerTokenFee(); + assertEq(fee, 10000000000000000); + } } diff --git a/contracts/test/mocks/GatewayMock.sol b/contracts/test/mocks/GatewayMock.sol index 6146dc058b..c2d7bbc5f8 100644 --- a/contracts/test/mocks/GatewayMock.sol +++ b/contracts/test/mocks/GatewayMock.sol @@ -80,6 +80,10 @@ contract GatewayMock is Gateway { function setTokenTransferFeesPublic(bytes calldata params) external { this.setTokenTransferFees(params); } + + function setPricingParametersPublic(bytes calldata params) external { + this.setPricingParameters(params); + } } library AdditionalStorage { diff --git a/contracts/test/mocks/GatewayUpgradeMock.sol b/contracts/test/mocks/GatewayUpgradeMock.sol index 87bd6884e1..952e0c41c3 100644 --- a/contracts/test/mocks/GatewayUpgradeMock.sol +++ b/contracts/test/mocks/GatewayUpgradeMock.sol @@ -6,6 +6,7 @@ import {Channel, InboundMessage, OperatingMode, ParaID, Command, ChannelID, Mult import {IGateway} from "../../src/interfaces/IGateway.sol"; import {IInitializable} from "../../src/interfaces/IInitializable.sol"; import {Verification} from "../../src/Verification.sol"; +import {UD60x18, convert} from "prb/math/src/UD60x18.sol"; contract GatewayUpgradeMock is IGateway, IInitializable { /** @@ -53,4 +54,8 @@ contract GatewayUpgradeMock is IGateway, IInitializable { (uint256 d0, uint256 d1) = abi.decode(data, (uint256, uint256)); emit Initialized(d0, d1); } + + function getPricingParameters() external view returns (UD60x18, uint128) { + return (convert(0), uint128(0)); + } } From ffa59e4943b730bd3a2ee7e57c3635561996e689 Mon Sep 17 00:00:00 2001 From: ron Date: Tue, 28 Nov 2023 09:58:15 +0800 Subject: [PATCH 15/38] Fix breaking tests --- .../inbound-queue/src/benchmarking/mod.rs | 2 +- parachain/pallets/inbound-queue/src/lib.rs | 3 + parachain/pallets/inbound-queue/src/mock.rs | 307 ++++++++++++++++++ parachain/pallets/inbound-queue/src/test.rs | 304 +---------------- parachain/pallets/outbound-queue/src/mock.rs | 2 +- parachain/pallets/outbound-queue/src/test.rs | 1 - 6 files changed, 317 insertions(+), 302 deletions(-) create mode 100644 parachain/pallets/inbound-queue/src/mock.rs diff --git a/parachain/pallets/inbound-queue/src/benchmarking/mod.rs b/parachain/pallets/inbound-queue/src/benchmarking/mod.rs index b97fd21cb0..93a99a2ec8 100644 --- a/parachain/pallets/inbound-queue/src/benchmarking/mod.rs +++ b/parachain/pallets/inbound-queue/src/benchmarking/mod.rs @@ -57,5 +57,5 @@ mod benchmarks { Ok(()) } - impl_benchmark_test_suite!(InboundQueue, crate::test::new_tester(), crate::test::Test); + impl_benchmark_test_suite!(InboundQueue, crate::mock::new_tester(), crate::mock::Test); } diff --git a/parachain/pallets/inbound-queue/src/lib.rs b/parachain/pallets/inbound-queue/src/lib.rs index bdd367ad23..67b581a491 100644 --- a/parachain/pallets/inbound-queue/src/lib.rs +++ b/parachain/pallets/inbound-queue/src/lib.rs @@ -33,6 +33,9 @@ use snowbridge_beacon_primitives::CompactExecutionHeader; pub mod weights; +#[cfg(test)] +mod mock; + #[cfg(test)] mod test; diff --git a/parachain/pallets/inbound-queue/src/mock.rs b/parachain/pallets/inbound-queue/src/mock.rs new file mode 100644 index 0000000000..123724b008 --- /dev/null +++ b/parachain/pallets/inbound-queue/src/mock.rs @@ -0,0 +1,307 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023 Snowfork +use super::*; + +use frame_support::{ + parameter_types, + traits::{ConstU128, Everything}, + weights::IdentityFee, +}; +use hex_literal::hex; +use snowbridge_beacon_primitives::{Fork, ForkVersions}; +use snowbridge_core::{ + gwei, + inbound::{Log, Proof, VerificationError}, + meth, Channel, ChannelId, PricingParameters, Rewards, StaticLookup, +}; +use snowbridge_router_primitives::inbound::MessageToXcm; +use sp_core::{H160, H256}; +use sp_runtime::{ + traits::{BlakeTwo256, IdentifyAccount, IdentityLookup, Verify}, + BuildStorage, FixedU128, MultiSignature, +}; +use sp_std::convert::From; +use xcm::v3::{prelude::*, MultiAssets, SendXcm}; + +use crate::{self as inbound_queue}; + +type Block = frame_system::mocking::MockBlock; + +frame_support::construct_runtime!( + pub enum Test + { + System: frame_system::{Pallet, Call, Storage, Event}, + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, + EthereumBeaconClient: snowbridge_ethereum_beacon_client::{Pallet, Call, Storage, Event}, + InboundQueue: inbound_queue::{Pallet, Call, Storage, Event}, + } +); + +pub type Signature = MultiSignature; +pub type AccountId = <::Signer as IdentifyAccount>::AccountId; + +parameter_types! { + pub const BlockHashCount: u64 = 250; +} + +type Balance = u128; + +impl frame_system::Config for Test { + type BaseCallFilter = Everything; + type BlockWeights = (); + type BlockLength = (); + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = BlockHashCount; + type DbWeight = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; + type Nonce = u64; + type Block = Block; +} + +impl pallet_balances::Config for Test { + type MaxLocks = (); + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type Balance = Balance; + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ConstU128<1>; + type AccountStore = System; + type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); + type MaxHolds = (); +} + +parameter_types! { + pub const ExecutionHeadersPruneThreshold: u32 = 10; + pub const ChainForkVersions: ForkVersions = ForkVersions{ + genesis: Fork { + version: [0, 0, 0, 1], // 0x00000001 + epoch: 0, + }, + altair: Fork { + version: [1, 0, 0, 1], // 0x01000001 + epoch: 0, + }, + bellatrix: Fork { + version: [2, 0, 0, 1], // 0x02000001 + epoch: 0, + }, + capella: Fork { + version: [3, 0, 0, 1], // 0x03000001 + epoch: 0, + }, + }; +} + +impl snowbridge_ethereum_beacon_client::Config for Test { + type RuntimeEvent = RuntimeEvent; + type ForkVersions = ChainForkVersions; + type MaxExecutionHeadersToKeep = ExecutionHeadersPruneThreshold; + type WeightInfo = (); +} + +// Mock verifier +pub struct MockVerifier; + +impl Verifier for MockVerifier { + fn verify(_: &Log, _: &Proof) -> Result<(), VerificationError> { + Ok(()) + } +} + +const GATEWAY_ADDRESS: [u8; 20] = hex!["eda338e4dc46038493b885327842fd3e301cab39"]; + +parameter_types! { + pub const EthereumNetwork: xcm::v3::NetworkId = xcm::v3::NetworkId::Ethereum { chain_id: 15 }; + pub const GatewayAddress: H160 = H160(GATEWAY_ADDRESS); + pub const CreateAssetCall: [u8;2] = [53, 0]; + pub const CreateAssetExecutionFee: u128 = 2_000_000_000; + pub const CreateAssetDeposit: u128 = 100_000_000_000; + pub const SendTokenExecutionFee: u128 = 1_000_000_000; + pub const InitialFund: u128 = 1_000_000_000_000; +} + +#[cfg(feature = "runtime-benchmarks")] +impl BenchmarkHelper for Test { + // not implemented since the MockVerifier is used for tests + fn initialize_storage(_: H256, _: CompactExecutionHeader) {} +} + +// Mock XCM sender that always succeeds +pub struct MockXcmSender; + +impl SendXcm for MockXcmSender { + type Ticket = Xcm<()>; + + fn validate( + dest: &mut Option, + xcm: &mut Option>, + ) -> SendResult { + match dest { + Some(MultiLocation { interior, .. }) => { + if let X1(Parachain(1001)) = interior { + return Err(XcmpSendError::NotApplicable) + } + Ok((xcm.clone().unwrap(), MultiAssets::default())) + }, + _ => Ok((xcm.clone().unwrap(), MultiAssets::default())), + } + } + + fn deliver(xcm: Self::Ticket) -> core::result::Result { + let hash = xcm.using_encoded(sp_io::hashing::blake2_256); + Ok(hash) + } +} + +parameter_types! { + pub const OwnParaId: ParaId = ParaId::new(1013); + pub Parameters: PricingParameters = PricingParameters { + exchange_rate: FixedU128::from_rational(1, 400), + fee_per_gas: gwei(20), + rewards: Rewards { local: 1 * DOT, remote: meth(1) } + }; +} + +pub const DOT: u128 = 10_000_000_000; + +pub struct MockChannelLookup; +impl StaticLookup for MockChannelLookup { + type Source = ChannelId; + type Target = Channel; + + fn lookup(channel_id: Self::Source) -> Option { + if channel_id != + hex!("c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539").into() + { + return None + } + Some(Channel { agent_id: H256::zero().into(), para_id: ASSET_HUB_PARAID.into() }) + } +} + +impl inbound_queue::Config for Test { + type RuntimeEvent = RuntimeEvent; + type Verifier = MockVerifier; + type Token = Balances; + type XcmSender = MockXcmSender; + type WeightInfo = (); + type GatewayAddress = GatewayAddress; + type MessageConverter = MessageToXcm< + CreateAssetCall, + CreateAssetExecutionFee, + CreateAssetDeposit, + AccountId, + Balance, + >; + type PricingParameters = Parameters; + type ChannelLookup = MockChannelLookup; + #[cfg(feature = "runtime-benchmarks")] + type Helper = Test; + type WeightToFee = IdentityFee; +} + +pub fn last_events(n: usize) -> Vec { + frame_system::Pallet::::events() + .into_iter() + .rev() + .take(n) + .rev() + .map(|e| e.event) + .collect() +} + +pub fn expect_events(e: Vec) { + assert_eq!(last_events(e.len()), e); +} + +pub fn setup() { + System::set_block_number(1); + Balances::mint_into( + &sibling_sovereign_account::(ASSET_HUB_PARAID.into()), + InitialFund::get(), + ) + .unwrap(); + Balances::mint_into( + &sibling_sovereign_account::(TEMPLATE_PARAID.into()), + InitialFund::get(), + ) + .unwrap(); +} + +pub fn new_tester() -> sp_io::TestExternalities { + let storage = frame_system::GenesisConfig::::default().build_storage().unwrap(); + let mut ext: sp_io::TestExternalities = storage.into(); + ext.execute_with(|| setup()); + ext +} + +// Generated from smoketests: +// cd smoketests +// ./make-bindings +// cargo test --test register_token -- --nocapture +pub fn mock_event_log() -> Log { + Log { + // gateway address + address: hex!("eda338e4dc46038493b885327842fd3e301cab39").into(), + topics: vec![ + hex!("7153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84f").into(), + // channel id + hex!("c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539").into(), + // message id + hex!("5f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0").into(), + ], + // Nonce + Payload + data: hex!("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001e000f000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d0000").into(), + } +} + +pub fn mock_event_log_invalid_channel() -> Log { + Log { + address: hex!("eda338e4dc46038493b885327842fd3e301cab39").into(), + topics: vec![ + hex!("7153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84f").into(), + // invalid channel id + hex!("0000000000000000000000000000000000000000000000000000000000000000").into(), + hex!("5f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0").into(), + ], + data: hex!("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001e000f000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d0000").into(), + } +} + +pub fn mock_event_log_invalid_gateway() -> Log { + Log { + // gateway address + address: H160::zero(), + topics: vec![ + hex!("7153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84f").into(), + // channel id + hex!("c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539").into(), + // message id + hex!("5f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0").into(), + ], + // Nonce + Payload + data: hex!("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001e000f000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d0000").into(), + } +} + +pub const ASSET_HUB_PARAID: u32 = 1000u32; +pub const TEMPLATE_PARAID: u32 = 1001u32; diff --git a/parachain/pallets/inbound-queue/src/test.rs b/parachain/pallets/inbound-queue/src/test.rs index 749ab2915c..875ae2e2a4 100644 --- a/parachain/pallets/inbound-queue/src/test.rs +++ b/parachain/pallets/inbound-queue/src/test.rs @@ -2,305 +2,16 @@ // SPDX-FileCopyrightText: 2023 Snowfork use super::*; -use frame_support::{ - assert_noop, assert_ok, parameter_types, - traits::{ConstU128, Everything}, - weights::IdentityFee, -}; +use frame_support::{assert_noop, assert_ok}; use hex_literal::hex; -use snowbridge_beacon_primitives::{Fork, ForkVersions}; -use snowbridge_core::{ - gwei, - inbound::{Log, Proof, VerificationError}, - meth, Channel, ChannelId, PricingParameters, Rewards, StaticLookup, -}; -use snowbridge_router_primitives::inbound::MessageToXcm; -use sp_core::{H160, H256}; +use snowbridge_core::{inbound::Proof, ChannelId}; use sp_keyring::AccountKeyring as Keyring; -use sp_runtime::{ - traits::{BlakeTwo256, IdentifyAccount, IdentityLookup, Verify}, - BuildStorage, DispatchError, FixedU128, MultiSignature, TokenError, -}; +use sp_runtime::{DispatchError, TokenError}; use sp_std::convert::From; -use xcm::v3::{prelude::*, MultiAssets, SendXcm}; -use crate::{self as inbound_queue, Error, Event as InboundQueueEvent}; +use crate::{Error, Event as InboundQueueEvent}; -type Block = frame_system::mocking::MockBlock; - -frame_support::construct_runtime!( - pub enum Test - { - System: frame_system::{Pallet, Call, Storage, Event}, - Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - EthereumBeaconClient: snowbridge_ethereum_beacon_client::{Pallet, Call, Storage, Event}, - InboundQueue: inbound_queue::{Pallet, Call, Storage, Event}, - } -); - -pub type Signature = MultiSignature; -pub type AccountId = <::Signer as IdentifyAccount>::AccountId; - -parameter_types! { - pub const BlockHashCount: u64 = 250; -} - -type Balance = u128; - -impl frame_system::Config for Test { - type BaseCallFilter = Everything; - type BlockWeights = (); - type BlockLength = (); - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = AccountId; - type Lookup = IdentityLookup; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = BlockHashCount; - type DbWeight = (); - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; - type Nonce = u64; - type Block = Block; -} - -impl pallet_balances::Config for Test { - type MaxLocks = (); - type MaxReserves = (); - type ReserveIdentifier = [u8; 8]; - type Balance = Balance; - type RuntimeEvent = RuntimeEvent; - type DustRemoval = (); - type ExistentialDeposit = ConstU128<1>; - type AccountStore = System; - type WeightInfo = (); - type FreezeIdentifier = (); - type MaxFreezes = (); - type RuntimeHoldReason = (); - type RuntimeFreezeReason = (); - type MaxHolds = (); -} - -parameter_types! { - pub const ExecutionHeadersPruneThreshold: u32 = 10; - pub const ChainForkVersions: ForkVersions = ForkVersions{ - genesis: Fork { - version: [0, 0, 0, 1], // 0x00000001 - epoch: 0, - }, - altair: Fork { - version: [1, 0, 0, 1], // 0x01000001 - epoch: 0, - }, - bellatrix: Fork { - version: [2, 0, 0, 1], // 0x02000001 - epoch: 0, - }, - capella: Fork { - version: [3, 0, 0, 1], // 0x03000001 - epoch: 0, - }, - }; -} - -impl snowbridge_ethereum_beacon_client::Config for Test { - type RuntimeEvent = RuntimeEvent; - type ForkVersions = ChainForkVersions; - type MaxExecutionHeadersToKeep = ExecutionHeadersPruneThreshold; - type WeightInfo = (); -} - -// Mock verifier -pub struct MockVerifier; - -impl Verifier for MockVerifier { - fn verify(_: &Log, _: &Proof) -> Result<(), VerificationError> { - Ok(()) - } -} - -const GATEWAY_ADDRESS: [u8; 20] = hex!["eda338e4dc46038493b885327842fd3e301cab39"]; - -parameter_types! { - pub const EthereumNetwork: xcm::v3::NetworkId = xcm::v3::NetworkId::Ethereum { chain_id: 15 }; - pub const GatewayAddress: H160 = H160(GATEWAY_ADDRESS); - pub const CreateAssetCall: [u8;2] = [53, 0]; - pub const CreateAssetExecutionFee: u128 = 2_000_000_000; - pub const CreateAssetDeposit: u128 = 100_000_000_000; - pub const SendTokenExecutionFee: u128 = 1_000_000_000; - pub const InitialFund: u128 = 1_000_000_000_000; -} - -#[cfg(feature = "runtime-benchmarks")] -impl BenchmarkHelper for Test { - // not implemented since the MockVerifier is used for tests - fn initialize_storage(_: H256, _: CompactExecutionHeader) {} -} - -// Mock XCM sender that always succeeds -pub struct MockXcmSender; - -impl SendXcm for MockXcmSender { - type Ticket = Xcm<()>; - - fn validate( - dest: &mut Option, - xcm: &mut Option>, - ) -> SendResult { - match dest { - Some(MultiLocation { interior, .. }) => { - if let X1(Parachain(1001)) = interior { - return Err(XcmpSendError::NotApplicable) - } - Ok((xcm.clone().unwrap(), MultiAssets::default())) - }, - _ => Ok((xcm.clone().unwrap(), MultiAssets::default())), - } - } - - fn deliver(xcm: Self::Ticket) -> core::result::Result { - let hash = xcm.using_encoded(sp_io::hashing::blake2_256); - Ok(hash) - } -} - -parameter_types! { - pub const OwnParaId: ParaId = ParaId::new(1013); - pub Parameters: PricingParameters = PricingParameters { - exchange_rate: FixedU128::from_rational(1, 400), - fee_per_gas: gwei(20), - rewards: Rewards { local: 1 * DOT, remote: meth(1) } - }; -} - -pub const DOT: u128 = 10_000_000_000; - -pub struct MockChannelLookup; -impl StaticLookup for MockChannelLookup { - type Source = ChannelId; - type Target = Channel; - - fn lookup(_: Self::Source) -> Option { - Some(Channel { agent_id: H256::zero().into(), para_id: Default::default() }) - } -} - -impl inbound_queue::Config for Test { - type RuntimeEvent = RuntimeEvent; - type Verifier = MockVerifier; - type Token = Balances; - type XcmSender = MockXcmSender; - type WeightInfo = (); - type GatewayAddress = GatewayAddress; - type MessageConverter = MessageToXcm< - CreateAssetCall, - CreateAssetExecutionFee, - CreateAssetDeposit, - AccountId, - Balance, - >; - type PricingParameters = Parameters; - type ChannelLookup = MockChannelLookup; - #[cfg(feature = "runtime-benchmarks")] - type Helper = Test; - type WeightToFee = IdentityFee; -} - -fn last_events(n: usize) -> Vec { - frame_system::Pallet::::events() - .into_iter() - .rev() - .take(n) - .rev() - .map(|e| e.event) - .collect() -} - -fn expect_events(e: Vec) { - assert_eq!(last_events(e.len()), e); -} - -fn setup() { - System::set_block_number(1); - Balances::mint_into( - &sibling_sovereign_account::(ASSET_HUB_PARAID.into()), - InitialFund::get(), - ) - .unwrap(); - Balances::mint_into( - &sibling_sovereign_account::(TEMPLATE_PARAID.into()), - InitialFund::get(), - ) - .unwrap(); -} - -pub fn new_tester() -> sp_io::TestExternalities { - let storage = frame_system::GenesisConfig::::default().build_storage().unwrap(); - let mut ext: sp_io::TestExternalities = storage.into(); - ext.execute_with(|| setup()); - ext -} - -// Generated from smoketests: -// cd smoketests -// ./make-bindings -// cargo test --test register_token -- --nocapture -fn mock_event_log() -> Log { - Log { - // gateway address - address: hex!("eda338e4dc46038493b885327842fd3e301cab39").into(), - topics: vec![ - hex!("7153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84f").into(), - // channel id - hex!("c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539").into(), - // message id - hex!("5f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0").into(), - ], - // Nonce + Payload - data: hex!("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001e000f000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d0000").into(), - } -} - -fn mock_event_log_invalid_channel() -> Log { - Log { - address: hex!("eda338e4dc46038493b885327842fd3e301cab39").into(), - topics: vec![ - hex!("7153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84f").into(), - // invalid channel id - hex!("0000000000000000000000000000000000000000000000000000000000000000").into(), - hex!("5f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0").into(), - ], - data: hex!("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001e000f000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d0000").into(), - } -} - -fn mock_event_log_invalid_gateway() -> Log { - Log { - // gateway address - address: H160::zero(), - topics: vec![ - hex!("7153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84f").into(), - // channel id - hex!("c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539").into(), - // message id - hex!("5f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0").into(), - ], - // Nonce + Payload - data: hex!("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001e000f000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d0000").into(), - } -} - -const ASSET_HUB_PARAID: u32 = 1000u32; -const TEMPLATE_PARAID: u32 = 1001u32; +use crate::mock::*; #[test] fn test_submit_happy_path() { @@ -308,11 +19,6 @@ fn test_submit_happy_path() { let relayer: AccountId = Keyring::Bob.into(); let origin = RuntimeOrigin::signed(relayer); - // Deposit funds into sovereign account of Asset Hub (Statemint) - let sovereign_account = sibling_sovereign_account::(ASSET_HUB_PARAID.into()); - println!("account: {}", sovereign_account); - let _ = Balances::mint_into(&sovereign_account, 10000); - // Submit message let message = Message { event_log: mock_event_log(), diff --git a/parachain/pallets/outbound-queue/src/mock.rs b/parachain/pallets/outbound-queue/src/mock.rs index 4504e48798..cf6c4c5899 100644 --- a/parachain/pallets/outbound-queue/src/mock.rs +++ b/parachain/pallets/outbound-queue/src/mock.rs @@ -12,7 +12,7 @@ use snowbridge_core::{ gwei, meth, outbound::*, pricing::{PricingParameters, Rewards}, - Channel, ChannelId, ParaId, PRIMARY_GOVERNANCE_CHANNEL, + ParaId, PRIMARY_GOVERNANCE_CHANNEL, }; use sp_core::{ConstU32, ConstU8, H160, H256}; use sp_runtime::{ diff --git a/parachain/pallets/outbound-queue/src/test.rs b/parachain/pallets/outbound-queue/src/test.rs index 7e49db16f1..1cf1f4b214 100644 --- a/parachain/pallets/outbound-queue/src/test.rs +++ b/parachain/pallets/outbound-queue/src/test.rs @@ -14,7 +14,6 @@ use snowbridge_core::{ ParaId, }; use sp_core::H256; -use sp_runtime::{AccountId32, DispatchError}; #[test] fn submit_messages_and_commit() { From c93468cc765c1dcec2c85cbddec0a5c61f0f136c Mon Sep 17 00:00:00 2001 From: ron Date: Tue, 28 Nov 2023 10:01:29 +0800 Subject: [PATCH 16/38] Merge main branch --- polkadot-sdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polkadot-sdk b/polkadot-sdk index acf10e64b0..d678f2e447 160000 --- a/polkadot-sdk +++ b/polkadot-sdk @@ -1 +1 @@ -Subproject commit acf10e64b056dd112cbf40ae26fb1fd81004a5d8 +Subproject commit d678f2e44777a12774e9f56a61d29ac5d1459498 From 3a996017954769cca3a0bccbe79f2932dd87e18f Mon Sep 17 00:00:00 2001 From: ron Date: Tue, 28 Nov 2023 12:24:01 +0800 Subject: [PATCH 17/38] Update sdk --- polkadot-sdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polkadot-sdk b/polkadot-sdk index 282762fe37..51cae29967 160000 --- a/polkadot-sdk +++ b/polkadot-sdk @@ -1 +1 @@ -Subproject commit 282762fe3748b9fa564631665e706721244109a4 +Subproject commit 51cae29967b2ad479e5721159797f1e5ddbb0433 From 0b24172a0a2c66922aaa5f61a7d9572222bcab37 Mon Sep 17 00:00:00 2001 From: ron Date: Tue, 28 Nov 2023 12:56:57 +0800 Subject: [PATCH 18/38] Load InboundDeliveryCost from EthereumInboundQueue --- parachain/pallets/control/src/lib.rs | 1 - parachain/pallets/inbound-queue/src/lib.rs | 19 ++++++++++--------- polkadot-sdk | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/parachain/pallets/control/src/lib.rs b/parachain/pallets/control/src/lib.rs index e254a0dc74..45bad5cdfa 100644 --- a/parachain/pallets/control/src/lib.rs +++ b/parachain/pallets/control/src/lib.rs @@ -158,7 +158,6 @@ pub mod pallet { type DefaultPricingParameters: Get>; /// Cost of delivering a message from Ethereum - /// Todo: Remove with a dynamic read from inbound queue type InboundDeliveryCost: Get>; type WeightInfo: WeightInfo; diff --git a/parachain/pallets/inbound-queue/src/lib.rs b/parachain/pallets/inbound-queue/src/lib.rs index 67b581a491..39a774bd82 100644 --- a/parachain/pallets/inbound-queue/src/lib.rs +++ b/parachain/pallets/inbound-queue/src/lib.rs @@ -248,18 +248,11 @@ pub mod pallet { } })?; - let pricing_parameters = T::PricingParameters::get(); - // Reward relayer from the sovereign account of the destination parachain // Expected to fail if sovereign account has no funds let sovereign_account = sibling_sovereign_account::(channel.para_id); - let refund = T::WeightToFee::weight_to_fee(&T::WeightInfo::submit()); - T::Token::transfer( - &sovereign_account, - &who, - refund.saturating_add(pricing_parameters.rewards.local), - Preservation::Preserve, - )?; + let delivery_cost = Self::get(); + T::Token::transfer(&sovereign_account, &who, delivery_cost, Preservation::Preserve)?; // Decode message into XCM let (xcm, fee) = @@ -316,4 +309,12 @@ pub mod pallet { Ok(xcm_hash) } } + + impl Get> for Pallet { + fn get() -> BalanceOf { + let pricing_parameters = T::PricingParameters::get(); + let refund: BalanceOf = T::WeightToFee::weight_to_fee(&T::WeightInfo::submit()); + refund.saturating_add(pricing_parameters.rewards.local) + } + } } diff --git a/polkadot-sdk b/polkadot-sdk index 51cae29967..eec6f38c8f 160000 --- a/polkadot-sdk +++ b/polkadot-sdk @@ -1 +1 @@ -Subproject commit 51cae29967b2ad479e5721159797f1e5ddbb0433 +Subproject commit eec6f38c8fb14ea96f2630477b074ad381b92c2a From 1618e7e635b21e75efa366ea627d3b539f605aa6 Mon Sep 17 00:00:00 2001 From: ron Date: Tue, 28 Nov 2023 18:13:10 +0800 Subject: [PATCH 19/38] Fix e2e setup & smoke tests --- contracts/src/DeployScript.sol | 8 +- parachain/pallets/control/src/lib.rs | 17 +- parachain/pallets/inbound-queue/src/lib.rs | 7 + parachain/primitives/core/src/outbound.rs | 13 +- polkadot-sdk | 2 +- relayer/contracts/gateway.go | 286 ++++++++++++++++----- smoketest/src/helper.rs | 17 +- smoketest/tests/register_token.rs | 21 +- smoketest/tests/send_token.rs | 14 +- smoketest/tests/set_token_transfer_fees.rs | 11 +- web/packages/test/scripts/set-env.sh | 11 +- 11 files changed, 299 insertions(+), 108 deletions(-) diff --git a/contracts/src/DeployScript.sol b/contracts/src/DeployScript.sol index e297db8d5a..c3b16d3579 100644 --- a/contracts/src/DeployScript.sol +++ b/contracts/src/DeployScript.sol @@ -82,10 +82,10 @@ contract DeployScript is Script { Gateway.Config memory config = Gateway.Config({ mode: defaultOperatingMode, - deliveryCost: uint128(vm.envUint("DEFAULT_FEE")), - registerTokenFee: uint128(vm.envUint("REGISTER_NATIVE_TOKEN_FEE")), - assetHubCreateAssetFee: uint128(vm.envUint("SEND_NATIVE_TOKEN_FEE")), - assetHubReserveTransferFee: uint128(vm.envUint("SEND_NATIVE_TOKEN_FEE")), + deliveryCost: uint128(vm.envUint("DELIVERY_COST")), + registerTokenFee: uint128(vm.envUint("REGISTER_TOKEN_FEE")), + assetHubCreateAssetFee: uint128(vm.envUint("CREATE_ASSET_FEE")), + assetHubReserveTransferFee: uint128(vm.envUint("RESERVE_TRANSFER_FEE")), exchangeRate: ud60x18(0.0025e18) }); diff --git a/parachain/pallets/control/src/lib.rs b/parachain/pallets/control/src/lib.rs index 45bad5cdfa..1e89b09c55 100644 --- a/parachain/pallets/control/src/lib.rs +++ b/parachain/pallets/control/src/lib.rs @@ -203,8 +203,9 @@ pub mod pallet { }, /// A SetTokenTransferFees message was sent to the Gateway SetTokenTransferFees { + create: u128, + transfer: u128, register: u128, - send: u128, }, PricingParametersChanged { params: PricingParametersOf, @@ -563,17 +564,21 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::set_token_transfer_fees())] pub fn set_token_transfer_fees( origin: OriginFor, + create: u128, + transfer: u128, register: u128, - send: u128, ) -> DispatchResult { ensure_root(origin)?; - ensure!(register > 0 && send > 0, Error::::InvalidTokenTransferFees); + ensure!( + create > 0 && transfer > 0 && register > 0, + Error::::InvalidTokenTransferFees + ); - let command = Command::SetTokenTransferFees { register, send }; - Self::send(SECONDARY_GOVERNANCE_CHANNEL, command, PaysFee::::No)?; + let command = Command::SetTokenTransferFees { create, transfer, register }; + Self::send(PRIMARY_GOVERNANCE_CHANNEL, command, PaysFee::::No)?; - Self::deposit_event(Event::::SetTokenTransferFees { register, send }); + Self::deposit_event(Event::::SetTokenTransferFees { register, create, transfer }); Ok(()) } } diff --git a/parachain/pallets/inbound-queue/src/lib.rs b/parachain/pallets/inbound-queue/src/lib.rs index 39a774bd82..a68a9e19a4 100644 --- a/parachain/pallets/inbound-queue/src/lib.rs +++ b/parachain/pallets/inbound-queue/src/lib.rs @@ -265,6 +265,13 @@ pub mod pallet { // so we must burn the amount of the fee embedded into the program. T::Token::burn_from(&sovereign_account, fee, Precision::Exact, Fortitude::Polite)?; + log::info!( + target: LOG_TARGET, + "💫 xcm {:?} sent with fee {:?}", + xcm, + fee + ); + // Attempt to send XCM to a dest parachain let message_id = Self::send_xcm(xcm, channel.para_id)?; diff --git a/parachain/primitives/core/src/outbound.rs b/parachain/primitives/core/src/outbound.rs index 68a3f84910..28dc399aae 100644 --- a/parachain/primitives/core/src/outbound.rs +++ b/parachain/primitives/core/src/outbound.rs @@ -118,10 +118,12 @@ mod v1 { }, /// Set token fees of the Gateway contract SetTokenTransferFees { - /// The fee for register token + /// The fee(DOT) for the cost of creating asset on AssetHub + create: u128, + /// The fee(DOT) for the cost of sending asset on AssetHub + transfer: u128, + /// The fee(Ether) for register an asset with reserve deposit and discourage spamming register: u128, - /// The fee for send token to para chain - send: u128, }, /// Set pricing parameters SetPricingParameters { @@ -187,10 +189,11 @@ mod v1 { Token::Address(*recipient), Token::Uint(U256::from(*amount)), ])]), - Command::SetTokenTransferFees { register, send } => + Command::SetTokenTransferFees { create, transfer, register } => ethabi::encode(&[Token::Tuple(vec![ + Token::Uint(U256::from(*create)), + Token::Uint(U256::from(*transfer)), Token::Uint(U256::from(*register)), - Token::Uint(U256::from(*send)), ])]), Command::SetPricingParameters { exchange_rate, delivery_cost } => ethabi::encode(&[Token::Tuple(vec![ diff --git a/polkadot-sdk b/polkadot-sdk index eec6f38c8f..ec3368061c 160000 --- a/polkadot-sdk +++ b/polkadot-sdk @@ -1 +1 @@ -Subproject commit eec6f38c8fb14ea96f2630477b074ad381b92c2a +Subproject commit ec3368061c1e4a9a4b05da6202ef59516a75abd3 diff --git a/relayer/contracts/gateway.go b/relayer/contracts/gateway.go index 8faab580c4..6f9d1ee4c1 100644 --- a/relayer/contracts/gateway.go +++ b/relayer/contracts/gateway.go @@ -91,7 +91,7 @@ type VerificationProof struct { // GatewayMetaData contains all meta data concerning the Gateway contract. var GatewayMetaData = &bind.MetaData{ - ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"agentID\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"agent\",\"type\":\"address\"}],\"name\":\"AgentCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"agentID\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"AgentFundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"ChannelID\",\"name\":\"channelID\",\"type\":\"bytes32\"}],\"name\":\"ChannelCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"ChannelID\",\"name\":\"channelID\",\"type\":\"bytes32\"}],\"name\":\"ChannelUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"ChannelID\",\"name\":\"channelID\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"messageID\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"name\":\"InboundMessageDispatched\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"enumOperatingMode\",\"name\":\"mode\",\"type\":\"uint8\"}],\"name\":\"OperatingModeChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"ChannelID\",\"name\":\"channelID\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"messageID\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"}],\"name\":\"OutboundMessageAccepted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"TokenRegistrationSent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"ParaID\",\"name\":\"destinationChain\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"enumKind\",\"name\":\"kind\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"indexed\":false,\"internalType\":\"structMultiAddress\",\"name\":\"destinationAddress\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"}],\"name\":\"TokenSent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"register\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"send\",\"type\":\"uint256\"}],\"name\":\"TokenTransferFeesChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"Upgraded\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"agentID\",\"type\":\"bytes32\"}],\"name\":\"agentOf\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"ChannelID\",\"name\":\"channelID\",\"type\":\"bytes32\"}],\"name\":\"channelNoncesOf\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"ChannelID\",\"name\":\"channelID\",\"type\":\"bytes32\"}],\"name\":\"channelOperatingModeOf\",\"outputs\":[{\"internalType\":\"enumOperatingMode\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"ChannelID\",\"name\":\"channelID\",\"type\":\"bytes32\"}],\"name\":\"channelOutboundFeeOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"implementation\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"operatingMode\",\"outputs\":[{\"internalType\":\"enumOperatingMode\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"registerToken\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"ParaID\",\"name\":\"destinationChain\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"enumKind\",\"name\":\"kind\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"internalType\":\"structMultiAddress\",\"name\":\"destinationAddress\",\"type\":\"tuple\"},{\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"}],\"name\":\"sendToken\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"ChannelID\",\"name\":\"channelID\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"internalType\":\"enumCommand\",\"name\":\"command\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"params\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"maxDispatchGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxRefund\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"reward\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"internalType\":\"structInboundMessage\",\"name\":\"message\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"leafProof\",\"type\":\"bytes32[]\"},{\"components\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"parentHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"number\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"extrinsicsRoot\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"kind\",\"type\":\"uint256\"},{\"internalType\":\"bytes4\",\"name\":\"consensusEngineID\",\"type\":\"bytes4\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"internalType\":\"structVerification.DigestItem[]\",\"name\":\"digestItems\",\"type\":\"tuple[]\"}],\"internalType\":\"structVerification.ParachainHeader\",\"name\":\"header\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"pos\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"width\",\"type\":\"uint256\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"internalType\":\"structVerification.HeadProof\",\"name\":\"headProof\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"parentNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"parentHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"nextAuthoritySetID\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"nextAuthoritySetLen\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"nextAuthoritySetRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structVerification.MMRLeafPartial\",\"name\":\"leafPartial\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"leafProof\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"leafProofOrder\",\"type\":\"uint256\"}],\"internalType\":\"structVerification.Proof\",\"name\":\"headerProof\",\"type\":\"tuple\"}],\"name\":\"submitInbound\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"tokenTransferFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"agentID\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"agent\",\"type\":\"address\"}],\"name\":\"AgentCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"agentID\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"AgentFundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"ChannelID\",\"name\":\"channelID\",\"type\":\"bytes32\"}],\"name\":\"ChannelCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"ChannelID\",\"name\":\"channelID\",\"type\":\"bytes32\"}],\"name\":\"ChannelUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"ChannelID\",\"name\":\"channelID\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"messageID\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"name\":\"InboundMessageDispatched\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"enumOperatingMode\",\"name\":\"mode\",\"type\":\"uint8\"}],\"name\":\"OperatingModeChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"ChannelID\",\"name\":\"channelID\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"messageID\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"}],\"name\":\"OutboundMessageAccepted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"PricingParametersChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"TokenRegistrationSent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"ParaID\",\"name\":\"destinationChain\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"enumKind\",\"name\":\"kind\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"indexed\":false,\"internalType\":\"structMultiAddress\",\"name\":\"destinationAddress\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"}],\"name\":\"TokenSent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"TokenTransferFeesChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"Upgraded\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"agentID\",\"type\":\"bytes32\"}],\"name\":\"agentOf\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"ChannelID\",\"name\":\"channelID\",\"type\":\"bytes32\"}],\"name\":\"channelNoncesOf\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"ChannelID\",\"name\":\"channelID\",\"type\":\"bytes32\"}],\"name\":\"channelOperatingModeOf\",\"outputs\":[{\"internalType\":\"enumOperatingMode\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPricingParameters\",\"outputs\":[{\"internalType\":\"UD60x18\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"implementation\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"operatingMode\",\"outputs\":[{\"internalType\":\"enumOperatingMode\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"registerToken\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"registerTokenFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"ParaID\",\"name\":\"destinationChain\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"enumKind\",\"name\":\"kind\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"internalType\":\"structMultiAddress\",\"name\":\"destinationAddress\",\"type\":\"tuple\"},{\"internalType\":\"uint128\",\"name\":\"destinationFee\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"}],\"name\":\"sendToken\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"ParaID\",\"name\":\"destinationChain\",\"type\":\"uint32\"},{\"internalType\":\"uint128\",\"name\":\"destinationFee\",\"type\":\"uint128\"}],\"name\":\"sendTokenFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"ChannelID\",\"name\":\"channelID\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"internalType\":\"enumCommand\",\"name\":\"command\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"params\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"maxDispatchGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxRefund\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"reward\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"internalType\":\"structInboundMessage\",\"name\":\"message\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"leafProof\",\"type\":\"bytes32[]\"},{\"components\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"parentHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"number\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"extrinsicsRoot\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"kind\",\"type\":\"uint256\"},{\"internalType\":\"bytes4\",\"name\":\"consensusEngineID\",\"type\":\"bytes4\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"internalType\":\"structVerification.DigestItem[]\",\"name\":\"digestItems\",\"type\":\"tuple[]\"}],\"internalType\":\"structVerification.ParachainHeader\",\"name\":\"header\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"pos\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"width\",\"type\":\"uint256\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"internalType\":\"structVerification.HeadProof\",\"name\":\"headProof\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"parentNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"parentHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"nextAuthoritySetID\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"nextAuthoritySetLen\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"nextAuthoritySetRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structVerification.MMRLeafPartial\",\"name\":\"leafPartial\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"leafProof\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"leafProofOrder\",\"type\":\"uint256\"}],\"internalType\":\"structVerification.Proof\",\"name\":\"headerProof\",\"type\":\"tuple\"}],\"name\":\"submitInbound\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", } // GatewayABI is the input ABI used to generate the binding from. @@ -334,35 +334,36 @@ func (_Gateway *GatewayCallerSession) ChannelOperatingModeOf(channelID [32]byte) return _Gateway.Contract.ChannelOperatingModeOf(&_Gateway.CallOpts, channelID) } -// ChannelOutboundFeeOf is a free data retrieval call binding the contract method 0x9af3378f. +// GetPricingParameters is a free data retrieval call binding the contract method 0xe92faaed. // -// Solidity: function channelOutboundFeeOf(bytes32 channelID) view returns(uint256) -func (_Gateway *GatewayCaller) ChannelOutboundFeeOf(opts *bind.CallOpts, channelID [32]byte) (*big.Int, error) { +// Solidity: function getPricingParameters() view returns(uint256, uint128) +func (_Gateway *GatewayCaller) GetPricingParameters(opts *bind.CallOpts) (*big.Int, *big.Int, error) { var out []interface{} - err := _Gateway.contract.Call(opts, &out, "channelOutboundFeeOf", channelID) + err := _Gateway.contract.Call(opts, &out, "getPricingParameters") if err != nil { - return *new(*big.Int), err + return *new(*big.Int), *new(*big.Int), err } out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + out1 := *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) - return out0, err + return out0, out1, err } -// ChannelOutboundFeeOf is a free data retrieval call binding the contract method 0x9af3378f. +// GetPricingParameters is a free data retrieval call binding the contract method 0xe92faaed. // -// Solidity: function channelOutboundFeeOf(bytes32 channelID) view returns(uint256) -func (_Gateway *GatewaySession) ChannelOutboundFeeOf(channelID [32]byte) (*big.Int, error) { - return _Gateway.Contract.ChannelOutboundFeeOf(&_Gateway.CallOpts, channelID) +// Solidity: function getPricingParameters() view returns(uint256, uint128) +func (_Gateway *GatewaySession) GetPricingParameters() (*big.Int, *big.Int, error) { + return _Gateway.Contract.GetPricingParameters(&_Gateway.CallOpts) } -// ChannelOutboundFeeOf is a free data retrieval call binding the contract method 0x9af3378f. +// GetPricingParameters is a free data retrieval call binding the contract method 0xe92faaed. // -// Solidity: function channelOutboundFeeOf(bytes32 channelID) view returns(uint256) -func (_Gateway *GatewayCallerSession) ChannelOutboundFeeOf(channelID [32]byte) (*big.Int, error) { - return _Gateway.Contract.ChannelOutboundFeeOf(&_Gateway.CallOpts, channelID) +// Solidity: function getPricingParameters() view returns(uint256, uint128) +func (_Gateway *GatewayCallerSession) GetPricingParameters() (*big.Int, *big.Int, error) { + return _Gateway.Contract.GetPricingParameters(&_Gateway.CallOpts) } // Implementation is a free data retrieval call binding the contract method 0x5c60da1b. @@ -427,36 +428,66 @@ func (_Gateway *GatewayCallerSession) OperatingMode() (uint8, error) { return _Gateway.Contract.OperatingMode(&_Gateway.CallOpts) } -// TokenTransferFees is a free data retrieval call binding the contract method 0xaef71eb4. +// RegisterTokenFee is a free data retrieval call binding the contract method 0x85f63dcb. // -// Solidity: function tokenTransferFees() view returns(uint256, uint256) -func (_Gateway *GatewayCaller) TokenTransferFees(opts *bind.CallOpts) (*big.Int, *big.Int, error) { +// Solidity: function registerTokenFee() view returns(uint256) +func (_Gateway *GatewayCaller) RegisterTokenFee(opts *bind.CallOpts) (*big.Int, error) { var out []interface{} - err := _Gateway.contract.Call(opts, &out, "tokenTransferFees") + err := _Gateway.contract.Call(opts, &out, "registerTokenFee") if err != nil { - return *new(*big.Int), *new(*big.Int), err + return *new(*big.Int), err } out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - out1 := *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) - return out0, out1, err + return out0, err } -// TokenTransferFees is a free data retrieval call binding the contract method 0xaef71eb4. +// RegisterTokenFee is a free data retrieval call binding the contract method 0x85f63dcb. // -// Solidity: function tokenTransferFees() view returns(uint256, uint256) -func (_Gateway *GatewaySession) TokenTransferFees() (*big.Int, *big.Int, error) { - return _Gateway.Contract.TokenTransferFees(&_Gateway.CallOpts) +// Solidity: function registerTokenFee() view returns(uint256) +func (_Gateway *GatewaySession) RegisterTokenFee() (*big.Int, error) { + return _Gateway.Contract.RegisterTokenFee(&_Gateway.CallOpts) } -// TokenTransferFees is a free data retrieval call binding the contract method 0xaef71eb4. +// RegisterTokenFee is a free data retrieval call binding the contract method 0x85f63dcb. // -// Solidity: function tokenTransferFees() view returns(uint256, uint256) -func (_Gateway *GatewayCallerSession) TokenTransferFees() (*big.Int, *big.Int, error) { - return _Gateway.Contract.TokenTransferFees(&_Gateway.CallOpts) +// Solidity: function registerTokenFee() view returns(uint256) +func (_Gateway *GatewayCallerSession) RegisterTokenFee() (*big.Int, error) { + return _Gateway.Contract.RegisterTokenFee(&_Gateway.CallOpts) +} + +// SendTokenFee is a free data retrieval call binding the contract method 0x783b4fab. +// +// Solidity: function sendTokenFee(address token, uint32 destinationChain, uint128 destinationFee) view returns(uint256) +func (_Gateway *GatewayCaller) SendTokenFee(opts *bind.CallOpts, token common.Address, destinationChain uint32, destinationFee *big.Int) (*big.Int, error) { + var out []interface{} + err := _Gateway.contract.Call(opts, &out, "sendTokenFee", token, destinationChain, destinationFee) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// SendTokenFee is a free data retrieval call binding the contract method 0x783b4fab. +// +// Solidity: function sendTokenFee(address token, uint32 destinationChain, uint128 destinationFee) view returns(uint256) +func (_Gateway *GatewaySession) SendTokenFee(token common.Address, destinationChain uint32, destinationFee *big.Int) (*big.Int, error) { + return _Gateway.Contract.SendTokenFee(&_Gateway.CallOpts, token, destinationChain, destinationFee) +} + +// SendTokenFee is a free data retrieval call binding the contract method 0x783b4fab. +// +// Solidity: function sendTokenFee(address token, uint32 destinationChain, uint128 destinationFee) view returns(uint256) +func (_Gateway *GatewayCallerSession) SendTokenFee(token common.Address, destinationChain uint32, destinationFee *big.Int) (*big.Int, error) { + return _Gateway.Contract.SendTokenFee(&_Gateway.CallOpts, token, destinationChain, destinationFee) } // RegisterToken is a paid mutator transaction binding the contract method 0x09824a80. @@ -480,25 +511,25 @@ func (_Gateway *GatewayTransactorSession) RegisterToken(token common.Address) (* return _Gateway.Contract.RegisterToken(&_Gateway.TransactOpts, token) } -// SendToken is a paid mutator transaction binding the contract method 0xb63ff1ae. +// SendToken is a paid mutator transaction binding the contract method 0x52054834. // -// Solidity: function sendToken(address token, uint32 destinationChain, (uint8,bytes) destinationAddress, uint128 amount) payable returns() -func (_Gateway *GatewayTransactor) SendToken(opts *bind.TransactOpts, token common.Address, destinationChain uint32, destinationAddress MultiAddress, amount *big.Int) (*types.Transaction, error) { - return _Gateway.contract.Transact(opts, "sendToken", token, destinationChain, destinationAddress, amount) +// Solidity: function sendToken(address token, uint32 destinationChain, (uint8,bytes) destinationAddress, uint128 destinationFee, uint128 amount) payable returns() +func (_Gateway *GatewayTransactor) SendToken(opts *bind.TransactOpts, token common.Address, destinationChain uint32, destinationAddress MultiAddress, destinationFee *big.Int, amount *big.Int) (*types.Transaction, error) { + return _Gateway.contract.Transact(opts, "sendToken", token, destinationChain, destinationAddress, destinationFee, amount) } -// SendToken is a paid mutator transaction binding the contract method 0xb63ff1ae. +// SendToken is a paid mutator transaction binding the contract method 0x52054834. // -// Solidity: function sendToken(address token, uint32 destinationChain, (uint8,bytes) destinationAddress, uint128 amount) payable returns() -func (_Gateway *GatewaySession) SendToken(token common.Address, destinationChain uint32, destinationAddress MultiAddress, amount *big.Int) (*types.Transaction, error) { - return _Gateway.Contract.SendToken(&_Gateway.TransactOpts, token, destinationChain, destinationAddress, amount) +// Solidity: function sendToken(address token, uint32 destinationChain, (uint8,bytes) destinationAddress, uint128 destinationFee, uint128 amount) payable returns() +func (_Gateway *GatewaySession) SendToken(token common.Address, destinationChain uint32, destinationAddress MultiAddress, destinationFee *big.Int, amount *big.Int) (*types.Transaction, error) { + return _Gateway.Contract.SendToken(&_Gateway.TransactOpts, token, destinationChain, destinationAddress, destinationFee, amount) } -// SendToken is a paid mutator transaction binding the contract method 0xb63ff1ae. +// SendToken is a paid mutator transaction binding the contract method 0x52054834. // -// Solidity: function sendToken(address token, uint32 destinationChain, (uint8,bytes) destinationAddress, uint128 amount) payable returns() -func (_Gateway *GatewayTransactorSession) SendToken(token common.Address, destinationChain uint32, destinationAddress MultiAddress, amount *big.Int) (*types.Transaction, error) { - return _Gateway.Contract.SendToken(&_Gateway.TransactOpts, token, destinationChain, destinationAddress, amount) +// Solidity: function sendToken(address token, uint32 destinationChain, (uint8,bytes) destinationAddress, uint128 destinationFee, uint128 amount) payable returns() +func (_Gateway *GatewayTransactorSession) SendToken(token common.Address, destinationChain uint32, destinationAddress MultiAddress, destinationFee *big.Int, amount *big.Int) (*types.Transaction, error) { + return _Gateway.Contract.SendToken(&_Gateway.TransactOpts, token, destinationChain, destinationAddress, destinationFee, amount) } // SubmitInbound is a paid mutator transaction binding the contract method 0xbd1026a1. @@ -1547,6 +1578,139 @@ func (_Gateway *GatewayFilterer) ParseOutboundMessageAccepted(log types.Log) (*G return event, nil } +// GatewayPricingParametersChangedIterator is returned from FilterPricingParametersChanged and is used to iterate over the raw logs and unpacked data for PricingParametersChanged events raised by the Gateway contract. +type GatewayPricingParametersChangedIterator struct { + Event *GatewayPricingParametersChanged // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *GatewayPricingParametersChangedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(GatewayPricingParametersChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(GatewayPricingParametersChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *GatewayPricingParametersChangedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *GatewayPricingParametersChangedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// GatewayPricingParametersChanged represents a PricingParametersChanged event raised by the Gateway contract. +type GatewayPricingParametersChanged struct { + Raw types.Log // Blockchain specific contextual infos +} + +// FilterPricingParametersChanged is a free log retrieval operation binding the contract event 0x5e3c25378b5946068b94aa2ea10c4c1e215cc975f994322b159ddc9237a973d4. +// +// Solidity: event PricingParametersChanged() +func (_Gateway *GatewayFilterer) FilterPricingParametersChanged(opts *bind.FilterOpts) (*GatewayPricingParametersChangedIterator, error) { + + logs, sub, err := _Gateway.contract.FilterLogs(opts, "PricingParametersChanged") + if err != nil { + return nil, err + } + return &GatewayPricingParametersChangedIterator{contract: _Gateway.contract, event: "PricingParametersChanged", logs: logs, sub: sub}, nil +} + +// WatchPricingParametersChanged is a free log subscription operation binding the contract event 0x5e3c25378b5946068b94aa2ea10c4c1e215cc975f994322b159ddc9237a973d4. +// +// Solidity: event PricingParametersChanged() +func (_Gateway *GatewayFilterer) WatchPricingParametersChanged(opts *bind.WatchOpts, sink chan<- *GatewayPricingParametersChanged) (event.Subscription, error) { + + logs, sub, err := _Gateway.contract.WatchLogs(opts, "PricingParametersChanged") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(GatewayPricingParametersChanged) + if err := _Gateway.contract.UnpackLog(event, "PricingParametersChanged", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParsePricingParametersChanged is a log parse operation binding the contract event 0x5e3c25378b5946068b94aa2ea10c4c1e215cc975f994322b159ddc9237a973d4. +// +// Solidity: event PricingParametersChanged() +func (_Gateway *GatewayFilterer) ParsePricingParametersChanged(log types.Log) (*GatewayPricingParametersChanged, error) { + event := new(GatewayPricingParametersChanged) + if err := _Gateway.contract.UnpackLog(event, "PricingParametersChanged", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + // GatewayTokenRegistrationSentIterator is returned from FilterTokenRegistrationSent and is used to iterate over the raw logs and unpacked data for TokenRegistrationSent events raised by the Gateway contract. type GatewayTokenRegistrationSentIterator struct { Event *GatewayTokenRegistrationSent // Event containing the contract specifics and raw log @@ -1760,8 +1924,8 @@ type GatewayTokenSent struct { // FilterTokenSent is a free log retrieval operation binding the contract event 0x24c5d2de620c6e25186ae16f6919eba93b6e2c1a33857cc419d9f3a00d6967e9. // -// Solidity: event TokenSent(address indexed token, address indexed sender, uint32 destinationChain, (uint8,bytes) destinationAddress, uint128 amount) -func (_Gateway *GatewayFilterer) FilterTokenSent(opts *bind.FilterOpts, token []common.Address, sender []common.Address) (*GatewayTokenSentIterator, error) { +// Solidity: event TokenSent(address indexed token, address indexed sender, uint32 indexed destinationChain, (uint8,bytes) destinationAddress, uint128 amount) +func (_Gateway *GatewayFilterer) FilterTokenSent(opts *bind.FilterOpts, token []common.Address, sender []common.Address, destinationChain []uint32) (*GatewayTokenSentIterator, error) { var tokenRule []interface{} for _, tokenItem := range token { @@ -1771,8 +1935,12 @@ func (_Gateway *GatewayFilterer) FilterTokenSent(opts *bind.FilterOpts, token [] for _, senderItem := range sender { senderRule = append(senderRule, senderItem) } + var destinationChainRule []interface{} + for _, destinationChainItem := range destinationChain { + destinationChainRule = append(destinationChainRule, destinationChainItem) + } - logs, sub, err := _Gateway.contract.FilterLogs(opts, "TokenSent", tokenRule, senderRule) + logs, sub, err := _Gateway.contract.FilterLogs(opts, "TokenSent", tokenRule, senderRule, destinationChainRule) if err != nil { return nil, err } @@ -1781,8 +1949,8 @@ func (_Gateway *GatewayFilterer) FilterTokenSent(opts *bind.FilterOpts, token [] // WatchTokenSent is a free log subscription operation binding the contract event 0x24c5d2de620c6e25186ae16f6919eba93b6e2c1a33857cc419d9f3a00d6967e9. // -// Solidity: event TokenSent(address indexed token, address indexed sender, uint32 destinationChain, (uint8,bytes) destinationAddress, uint128 amount) -func (_Gateway *GatewayFilterer) WatchTokenSent(opts *bind.WatchOpts, sink chan<- *GatewayTokenSent, token []common.Address, sender []common.Address) (event.Subscription, error) { +// Solidity: event TokenSent(address indexed token, address indexed sender, uint32 indexed destinationChain, (uint8,bytes) destinationAddress, uint128 amount) +func (_Gateway *GatewayFilterer) WatchTokenSent(opts *bind.WatchOpts, sink chan<- *GatewayTokenSent, token []common.Address, sender []common.Address, destinationChain []uint32) (event.Subscription, error) { var tokenRule []interface{} for _, tokenItem := range token { @@ -1792,8 +1960,12 @@ func (_Gateway *GatewayFilterer) WatchTokenSent(opts *bind.WatchOpts, sink chan< for _, senderItem := range sender { senderRule = append(senderRule, senderItem) } + var destinationChainRule []interface{} + for _, destinationChainItem := range destinationChain { + destinationChainRule = append(destinationChainRule, destinationChainItem) + } - logs, sub, err := _Gateway.contract.WatchLogs(opts, "TokenSent", tokenRule, senderRule) + logs, sub, err := _Gateway.contract.WatchLogs(opts, "TokenSent", tokenRule, senderRule, destinationChainRule) if err != nil { return nil, err } @@ -1827,7 +1999,7 @@ func (_Gateway *GatewayFilterer) WatchTokenSent(opts *bind.WatchOpts, sink chan< // ParseTokenSent is a log parse operation binding the contract event 0x24c5d2de620c6e25186ae16f6919eba93b6e2c1a33857cc419d9f3a00d6967e9. // -// Solidity: event TokenSent(address indexed token, address indexed sender, uint32 destinationChain, (uint8,bytes) destinationAddress, uint128 amount) +// Solidity: event TokenSent(address indexed token, address indexed sender, uint32 indexed destinationChain, (uint8,bytes) destinationAddress, uint128 amount) func (_Gateway *GatewayFilterer) ParseTokenSent(log types.Log) (*GatewayTokenSent, error) { event := new(GatewayTokenSent) if err := _Gateway.contract.UnpackLog(event, "TokenSent", log); err != nil { @@ -1906,14 +2078,12 @@ func (it *GatewayTokenTransferFeesChangedIterator) Close() error { // GatewayTokenTransferFeesChanged represents a TokenTransferFeesChanged event raised by the Gateway contract. type GatewayTokenTransferFeesChanged struct { - Register *big.Int - Send *big.Int - Raw types.Log // Blockchain specific contextual infos + Raw types.Log // Blockchain specific contextual infos } -// FilterTokenTransferFeesChanged is a free log retrieval operation binding the contract event 0xf8b9e90b8d22eedd745a43851ee14b456fc1ca0e7248defe1ee10a9619c897ed. +// FilterTokenTransferFeesChanged is a free log retrieval operation binding the contract event 0x4793c0cb5bef4b1fdbbfbcf17e06991844eb881088b012442af17a12ff38d5cd. // -// Solidity: event TokenTransferFeesChanged(uint256 register, uint256 send) +// Solidity: event TokenTransferFeesChanged() func (_Gateway *GatewayFilterer) FilterTokenTransferFeesChanged(opts *bind.FilterOpts) (*GatewayTokenTransferFeesChangedIterator, error) { logs, sub, err := _Gateway.contract.FilterLogs(opts, "TokenTransferFeesChanged") @@ -1923,9 +2093,9 @@ func (_Gateway *GatewayFilterer) FilterTokenTransferFeesChanged(opts *bind.Filte return &GatewayTokenTransferFeesChangedIterator{contract: _Gateway.contract, event: "TokenTransferFeesChanged", logs: logs, sub: sub}, nil } -// WatchTokenTransferFeesChanged is a free log subscription operation binding the contract event 0xf8b9e90b8d22eedd745a43851ee14b456fc1ca0e7248defe1ee10a9619c897ed. +// WatchTokenTransferFeesChanged is a free log subscription operation binding the contract event 0x4793c0cb5bef4b1fdbbfbcf17e06991844eb881088b012442af17a12ff38d5cd. // -// Solidity: event TokenTransferFeesChanged(uint256 register, uint256 send) +// Solidity: event TokenTransferFeesChanged() func (_Gateway *GatewayFilterer) WatchTokenTransferFeesChanged(opts *bind.WatchOpts, sink chan<- *GatewayTokenTransferFeesChanged) (event.Subscription, error) { logs, sub, err := _Gateway.contract.WatchLogs(opts, "TokenTransferFeesChanged") @@ -1960,9 +2130,9 @@ func (_Gateway *GatewayFilterer) WatchTokenTransferFeesChanged(opts *bind.WatchO }), nil } -// ParseTokenTransferFeesChanged is a log parse operation binding the contract event 0xf8b9e90b8d22eedd745a43851ee14b456fc1ca0e7248defe1ee10a9619c897ed. +// ParseTokenTransferFeesChanged is a log parse operation binding the contract event 0x4793c0cb5bef4b1fdbbfbcf17e06991844eb881088b012442af17a12ff38d5cd. // -// Solidity: event TokenTransferFeesChanged(uint256 register, uint256 send) +// Solidity: event TokenTransferFeesChanged() func (_Gateway *GatewayFilterer) ParseTokenTransferFeesChanged(log types.Log) (*GatewayTokenTransferFeesChanged, error) { event := new(GatewayTokenTransferFeesChanged) if err := _Gateway.contract.UnpackLog(event, "TokenTransferFeesChanged", log); err != nil { diff --git a/smoketest/src/helper.rs b/smoketest/src/helper.rs index 9c4af585f3..f2f1f53979 100644 --- a/smoketest/src/helper.rs +++ b/smoketest/src/helper.rs @@ -43,6 +43,7 @@ use ethers::{ TransactionRequest, Ws, U256, }, providers::Http, + types::Log, }; use futures::StreamExt; use sp_core::{sr25519::Pair, Pair as PairT, H160}; @@ -283,7 +284,7 @@ pub async fn construct_create_channel_call( bridge_hub_client: &Box>, ) -> Result, Box> { let call = bridgehub::api::ethereum_control::calls::TransactionApi - .create_channel(OperatingMode::Normal, 1) + .create_channel(OperatingMode::Normal) .encode_call_data(&bridge_hub_client.metadata())?; Ok(call) @@ -368,3 +369,17 @@ pub async fn fund_agent(agent_id: [u8; 32]) -> Result<(), Box = log.topics.iter().map(|t| hex::encode(t.as_ref())).collect(); + println!("Log {{"); + println!(" address: hex!(\"{}\").into(),", hex::encode(log.address.as_ref())); + println!(" topics: vec!["); + for topic in topics.iter() { + println!(" hex!(\"{}\").into(),", topic); + } + println!(" ],"); + println!(" data: hex!(\"{}\").into(),", hex::encode(&log.data)); + + println!("}}") +} diff --git a/smoketest/tests/register_token.rs b/smoketest/tests/register_token.rs index c83fdd2685..db4c6ae7e7 100644 --- a/smoketest/tests/register_token.rs +++ b/smoketest/tests/register_token.rs @@ -1,13 +1,10 @@ use codec::Encode; -use ethers::{ - core::types::{Address, Log}, - utils::parse_units, -}; +use ethers::{core::types::Address, utils::parse_units}; use futures::StreamExt; use snowbridge_smoketest::{ constants::*, contracts::{i_gateway, weth9}, - helper::initial_clients, + helper::{initial_clients, print_event_log_for_unit_tests}, parachains::assethub::api::{ foreign_assets::events::Created, runtime_types::{ @@ -95,17 +92,3 @@ async fn register_token() { } assert!(created_event_found) } - -fn print_event_log_for_unit_tests(log: &Log) { - let topics: Vec = log.topics.iter().map(|t| hex::encode(t.as_ref())).collect(); - println!("Log {{"); - println!(" address: hex!(\"{}\").into(),", hex::encode(log.address.as_ref())); - println!(" topics: vec!["); - for topic in topics.iter() { - println!(" hex!(\"{}\").into(),", topic); - } - println!(" ],"); - println!(" data: hex!(\"{}\").into(),", hex::encode(&log.data)); - - println!("}}") -} diff --git a/smoketest/tests/send_token.rs b/smoketest/tests/send_token.rs index ed32080cac..d22d2c8726 100644 --- a/smoketest/tests/send_token.rs +++ b/smoketest/tests/send_token.rs @@ -6,7 +6,7 @@ use futures::StreamExt; use snowbridge_smoketest::{ constants::*, contracts::{i_gateway, weth9}, - helper::initial_clients, + helper::{initial_clients, print_event_log_for_unit_tests}, parachains::assethub::api::{ foreign_assets::events::Issued, runtime_types::{ @@ -53,14 +53,16 @@ async fn send_token() { // Lock tokens into vault let amount: u128 = U256::from(value).low_u128(); + let fee: u128 = 1_000_000_000_000_000; let receipt = gateway .send_token( weth.address(), ASSET_HUB_PARA_ID, i_gateway::MultiAddress { kind: 1, data: FERDIE.into() }, + 0, amount, ) - .value(1000) + .value(fee) .send() .await .unwrap() @@ -68,7 +70,13 @@ async fn send_token() { .unwrap() .unwrap(); - println!("receipt: {:#?}", receipt); + println!("receipt transaction hash: {:#?}", hex::encode(receipt.transaction_hash)); + + // 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); diff --git a/smoketest/tests/set_token_transfer_fees.rs b/smoketest/tests/set_token_transfer_fees.rs index b1bc694ea0..c88ab28f1c 100644 --- a/smoketest/tests/set_token_transfer_fees.rs +++ b/smoketest/tests/set_token_transfer_fees.rs @@ -16,13 +16,14 @@ async fn set_token_transfer_fees() { let gateway_addr: Address = GATEWAY_PROXY_CONTRACT.into(); let ethereum_client = *(test_clients.ethereum_client.clone()); let gateway = i_gateway::IGateway::new(gateway_addr, ethereum_client.clone()); - let fees = gateway.token_transfer_fees().await.expect("get fees"); - println!("asset fees {:?}", fees); + let fees = gateway.register_token_fee().await.expect("get fees"); + println!("register fees {:?}", fees); let set_token_fees_call = BHRuntimeCall::EthereumControl( runtime_types::snowbridge_control::pallet::Call::set_token_transfer_fees { - register: 10_000_000_000_000, - send: 20_000_000_000, + create: 10_000_000_000_000, + transfer: 20_000_000_000, + register: 100_000_000_000_000_000, //0.1 Ether }, ); @@ -34,6 +35,6 @@ async fn set_token_transfer_fees() { wait_for_ethereum_event::(&test_clients.ethereum_client).await; - let fees = gateway.token_transfer_fees().await.expect("get fees"); + let fees = gateway.register_token_fee().await.expect("get fees"); println!("asset fees {:?}", fees); } diff --git a/web/packages/test/scripts/set-env.sh b/web/packages/test/scripts/set-env.sh index 7e9753c814..0451baf09f 100755 --- a/web/packages/test/scripts/set-env.sh +++ b/web/packages/test/scripts/set-env.sh @@ -85,17 +85,16 @@ export RANDAO_COMMIT_EXP="${ETH_RANDAO_EXP:-3}" export MINIMUM_REQUIRED_SIGNATURES="${MINIMUM_REQUIRED_SIGNATURES:-16}" export REJECT_OUTBOUND_MESSAGES=false -export DEFAULT_FEE="${ETH_DEFAULT_FEE:-1}" -export CREATE_CALL_INDEX="${ETH_CREATE_CALL_INDEX:-0x3500}" - -export REGISTER_NATIVE_TOKEN_FEE="${ETH_REGISTER_NATIVE_TOKEN_FEE:-0}" -export SEND_NATIVE_TOKEN_FEE="${ETH_SEND_NATIVE_TOKEN_FEE:-0}" +## Fee +export REGISTER_TOKEN_FEE="${REGISTER_TOKEN_FEE:-100000000000000000}" +export DELIVERY_COST="${DELIVERY_COST:-10000000000}" +export CREATE_ASSET_FEE="${CREATE_ASSET_FEE:-10000000000}" +export RESERVE_TRANSFER_FEE="${RESERVE_TRANSFER_FEE:-10000000000}" ## Vault export BRIDGE_HUB_INITIAL_DEPOSIT="${ETH_BRIDGE_HUB_INITIAL_DEPOSIT:-10000000000000000000}" - export GATEWAY_PROXY_CONTRACT="${GATEWAY_PROXY_CONTRACT:-0xEDa338E4dC46038493b885327842fD3E301CaB39}" address_for() { From 94e0949db46b33f7fe1ab051013f42e4bee2da5e Mon Sep 17 00:00:00 2001 From: ron Date: Tue, 28 Nov 2023 22:04:29 +0800 Subject: [PATCH 20/38] Fix for compact scale --- contracts/src/Types.sol | 2 +- contracts/test/Gateway.t.sol | 6 +-- contracts/test/mocks/GatewayUpgradeMock.sol | 2 +- relayer/contracts/gateway.go | 16 +++--- relayer/relays/parachain/scanner.go | 18 +++++-- relayer/relays/parachain/types.go | 59 +++++++++++++++++++-- 6 files changed, 83 insertions(+), 20 deletions(-) diff --git a/contracts/src/Types.sol b/contracts/src/Types.sol index 8180f7fa85..fa762750ac 100644 --- a/contracts/src/Types.sol +++ b/contracts/src/Types.sol @@ -60,7 +60,7 @@ struct InboundMessage { /// @dev The Parameters for the command bytes params; /// @dev The maximum gas allowed for message dispatch - uint256 maxDispatchGas; + uint64 maxDispatchGas; /// @dev The maximum gas refund for message submission uint256 maxRefund; /// @dev The reward for message submission diff --git a/contracts/test/Gateway.t.sol b/contracts/test/Gateway.t.sol index 289460a8f5..bd0588292d 100644 --- a/contracts/test/Gateway.t.sol +++ b/contracts/test/Gateway.t.sol @@ -59,7 +59,7 @@ contract GatewayTest is Test { address public account1; address public account2; - uint256 public maxDispatchGas = 500_000; + uint64 public maxDispatchGas = 500_000; uint256 public maxRefund = 1 ether; uint256 public reward = 1 ether; bytes32 public messageID = keccak256("cabbage"); @@ -743,9 +743,7 @@ contract GatewayTest is Test { OperatingMode channelMode = gw.channelOperatingModeOf(assetHubParaID.into()); assertEq(uint256(channelMode), 0); - PricingStorage.Layout storage pricing = PricingStorage.layout(); - - (UD60x18 _exchangeRate, uint128 fee) = gw.getPricingParameters(); + (, uint128 fee) = gw.getPricingParameters(); assertEq(fee, 10000000000); (uint64 inbound, uint64 outbound) = gw.channelNoncesOf(assetHubParaID.into()); diff --git a/contracts/test/mocks/GatewayUpgradeMock.sol b/contracts/test/mocks/GatewayUpgradeMock.sol index 952e0c41c3..fc46119a3a 100644 --- a/contracts/test/mocks/GatewayUpgradeMock.sol +++ b/contracts/test/mocks/GatewayUpgradeMock.sol @@ -55,7 +55,7 @@ contract GatewayUpgradeMock is IGateway, IInitializable { emit Initialized(d0, d1); } - function getPricingParameters() external view returns (UD60x18, uint128) { + function getPricingParameters() external pure returns (UD60x18, uint128) { return (convert(0), uint128(0)); } } diff --git a/relayer/contracts/gateway.go b/relayer/contracts/gateway.go index 6f9d1ee4c1..ae1a9e87ad 100644 --- a/relayer/contracts/gateway.go +++ b/relayer/contracts/gateway.go @@ -35,7 +35,7 @@ type InboundMessage struct { Nonce uint64 Command uint8 Params []byte - MaxDispatchGas *big.Int + MaxDispatchGas uint64 MaxRefund *big.Int Reward *big.Int Id [32]byte @@ -91,7 +91,7 @@ type VerificationProof struct { // GatewayMetaData contains all meta data concerning the Gateway contract. var GatewayMetaData = &bind.MetaData{ - ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"agentID\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"agent\",\"type\":\"address\"}],\"name\":\"AgentCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"agentID\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"AgentFundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"ChannelID\",\"name\":\"channelID\",\"type\":\"bytes32\"}],\"name\":\"ChannelCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"ChannelID\",\"name\":\"channelID\",\"type\":\"bytes32\"}],\"name\":\"ChannelUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"ChannelID\",\"name\":\"channelID\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"messageID\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"name\":\"InboundMessageDispatched\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"enumOperatingMode\",\"name\":\"mode\",\"type\":\"uint8\"}],\"name\":\"OperatingModeChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"ChannelID\",\"name\":\"channelID\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"messageID\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"}],\"name\":\"OutboundMessageAccepted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"PricingParametersChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"TokenRegistrationSent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"ParaID\",\"name\":\"destinationChain\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"enumKind\",\"name\":\"kind\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"indexed\":false,\"internalType\":\"structMultiAddress\",\"name\":\"destinationAddress\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"}],\"name\":\"TokenSent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"TokenTransferFeesChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"Upgraded\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"agentID\",\"type\":\"bytes32\"}],\"name\":\"agentOf\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"ChannelID\",\"name\":\"channelID\",\"type\":\"bytes32\"}],\"name\":\"channelNoncesOf\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"ChannelID\",\"name\":\"channelID\",\"type\":\"bytes32\"}],\"name\":\"channelOperatingModeOf\",\"outputs\":[{\"internalType\":\"enumOperatingMode\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPricingParameters\",\"outputs\":[{\"internalType\":\"UD60x18\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"implementation\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"operatingMode\",\"outputs\":[{\"internalType\":\"enumOperatingMode\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"registerToken\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"registerTokenFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"ParaID\",\"name\":\"destinationChain\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"enumKind\",\"name\":\"kind\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"internalType\":\"structMultiAddress\",\"name\":\"destinationAddress\",\"type\":\"tuple\"},{\"internalType\":\"uint128\",\"name\":\"destinationFee\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"}],\"name\":\"sendToken\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"ParaID\",\"name\":\"destinationChain\",\"type\":\"uint32\"},{\"internalType\":\"uint128\",\"name\":\"destinationFee\",\"type\":\"uint128\"}],\"name\":\"sendTokenFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"ChannelID\",\"name\":\"channelID\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"internalType\":\"enumCommand\",\"name\":\"command\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"params\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"maxDispatchGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxRefund\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"reward\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"internalType\":\"structInboundMessage\",\"name\":\"message\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"leafProof\",\"type\":\"bytes32[]\"},{\"components\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"parentHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"number\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"extrinsicsRoot\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"kind\",\"type\":\"uint256\"},{\"internalType\":\"bytes4\",\"name\":\"consensusEngineID\",\"type\":\"bytes4\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"internalType\":\"structVerification.DigestItem[]\",\"name\":\"digestItems\",\"type\":\"tuple[]\"}],\"internalType\":\"structVerification.ParachainHeader\",\"name\":\"header\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"pos\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"width\",\"type\":\"uint256\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"internalType\":\"structVerification.HeadProof\",\"name\":\"headProof\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"parentNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"parentHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"nextAuthoritySetID\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"nextAuthoritySetLen\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"nextAuthoritySetRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structVerification.MMRLeafPartial\",\"name\":\"leafPartial\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"leafProof\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"leafProofOrder\",\"type\":\"uint256\"}],\"internalType\":\"structVerification.Proof\",\"name\":\"headerProof\",\"type\":\"tuple\"}],\"name\":\"submitInbound\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"agentID\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"agent\",\"type\":\"address\"}],\"name\":\"AgentCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"agentID\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"AgentFundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"ChannelID\",\"name\":\"channelID\",\"type\":\"bytes32\"}],\"name\":\"ChannelCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"ChannelID\",\"name\":\"channelID\",\"type\":\"bytes32\"}],\"name\":\"ChannelUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"ChannelID\",\"name\":\"channelID\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"messageID\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"name\":\"InboundMessageDispatched\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"enumOperatingMode\",\"name\":\"mode\",\"type\":\"uint8\"}],\"name\":\"OperatingModeChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"ChannelID\",\"name\":\"channelID\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"messageID\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"}],\"name\":\"OutboundMessageAccepted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"PricingParametersChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"TokenRegistrationSent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"ParaID\",\"name\":\"destinationChain\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"enumKind\",\"name\":\"kind\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"indexed\":false,\"internalType\":\"structMultiAddress\",\"name\":\"destinationAddress\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"}],\"name\":\"TokenSent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"TokenTransferFeesChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"Upgraded\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"agentID\",\"type\":\"bytes32\"}],\"name\":\"agentOf\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"ChannelID\",\"name\":\"channelID\",\"type\":\"bytes32\"}],\"name\":\"channelNoncesOf\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"ChannelID\",\"name\":\"channelID\",\"type\":\"bytes32\"}],\"name\":\"channelOperatingModeOf\",\"outputs\":[{\"internalType\":\"enumOperatingMode\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPricingParameters\",\"outputs\":[{\"internalType\":\"UD60x18\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"implementation\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"operatingMode\",\"outputs\":[{\"internalType\":\"enumOperatingMode\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"registerToken\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"registerTokenFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"ParaID\",\"name\":\"destinationChain\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"enumKind\",\"name\":\"kind\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"internalType\":\"structMultiAddress\",\"name\":\"destinationAddress\",\"type\":\"tuple\"},{\"internalType\":\"uint128\",\"name\":\"destinationFee\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"}],\"name\":\"sendToken\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"ParaID\",\"name\":\"destinationChain\",\"type\":\"uint32\"},{\"internalType\":\"uint128\",\"name\":\"destinationFee\",\"type\":\"uint128\"}],\"name\":\"sendTokenFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"ChannelID\",\"name\":\"channelID\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"internalType\":\"enumCommand\",\"name\":\"command\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"params\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"maxDispatchGas\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"maxRefund\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"reward\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"internalType\":\"structInboundMessage\",\"name\":\"message\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"leafProof\",\"type\":\"bytes32[]\"},{\"components\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"parentHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"number\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"extrinsicsRoot\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"kind\",\"type\":\"uint256\"},{\"internalType\":\"bytes4\",\"name\":\"consensusEngineID\",\"type\":\"bytes4\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"internalType\":\"structVerification.DigestItem[]\",\"name\":\"digestItems\",\"type\":\"tuple[]\"}],\"internalType\":\"structVerification.ParachainHeader\",\"name\":\"header\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"pos\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"width\",\"type\":\"uint256\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"internalType\":\"structVerification.HeadProof\",\"name\":\"headProof\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"parentNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"parentHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"nextAuthoritySetID\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"nextAuthoritySetLen\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"nextAuthoritySetRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structVerification.MMRLeafPartial\",\"name\":\"leafPartial\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"leafProof\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"leafProofOrder\",\"type\":\"uint256\"}],\"internalType\":\"structVerification.Proof\",\"name\":\"headerProof\",\"type\":\"tuple\"}],\"name\":\"submitInbound\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", } // GatewayABI is the input ABI used to generate the binding from. @@ -532,23 +532,23 @@ func (_Gateway *GatewayTransactorSession) SendToken(token common.Address, destin return _Gateway.Contract.SendToken(&_Gateway.TransactOpts, token, destinationChain, destinationAddress, destinationFee, amount) } -// SubmitInbound is a paid mutator transaction binding the contract method 0xbd1026a1. +// SubmitInbound is a paid mutator transaction binding the contract method 0x02d12769. // -// Solidity: function submitInbound((bytes32,uint64,uint8,bytes,uint256,uint256,uint256,bytes32) message, bytes32[] leafProof, ((bytes32,uint256,bytes32,bytes32,(uint256,bytes4,bytes)[]),(uint256,uint256,bytes32[]),(uint8,uint32,bytes32,uint64,uint32,bytes32),bytes32[],uint256) headerProof) returns() +// Solidity: function submitInbound((bytes32,uint64,uint8,bytes,uint64,uint256,uint256,bytes32) message, bytes32[] leafProof, ((bytes32,uint256,bytes32,bytes32,(uint256,bytes4,bytes)[]),(uint256,uint256,bytes32[]),(uint8,uint32,bytes32,uint64,uint32,bytes32),bytes32[],uint256) headerProof) returns() func (_Gateway *GatewayTransactor) SubmitInbound(opts *bind.TransactOpts, message InboundMessage, leafProof [][32]byte, headerProof VerificationProof) (*types.Transaction, error) { return _Gateway.contract.Transact(opts, "submitInbound", message, leafProof, headerProof) } -// SubmitInbound is a paid mutator transaction binding the contract method 0xbd1026a1. +// SubmitInbound is a paid mutator transaction binding the contract method 0x02d12769. // -// Solidity: function submitInbound((bytes32,uint64,uint8,bytes,uint256,uint256,uint256,bytes32) message, bytes32[] leafProof, ((bytes32,uint256,bytes32,bytes32,(uint256,bytes4,bytes)[]),(uint256,uint256,bytes32[]),(uint8,uint32,bytes32,uint64,uint32,bytes32),bytes32[],uint256) headerProof) returns() +// Solidity: function submitInbound((bytes32,uint64,uint8,bytes,uint64,uint256,uint256,bytes32) message, bytes32[] leafProof, ((bytes32,uint256,bytes32,bytes32,(uint256,bytes4,bytes)[]),(uint256,uint256,bytes32[]),(uint8,uint32,bytes32,uint64,uint32,bytes32),bytes32[],uint256) headerProof) returns() func (_Gateway *GatewaySession) SubmitInbound(message InboundMessage, leafProof [][32]byte, headerProof VerificationProof) (*types.Transaction, error) { return _Gateway.Contract.SubmitInbound(&_Gateway.TransactOpts, message, leafProof, headerProof) } -// SubmitInbound is a paid mutator transaction binding the contract method 0xbd1026a1. +// SubmitInbound is a paid mutator transaction binding the contract method 0x02d12769. // -// Solidity: function submitInbound((bytes32,uint64,uint8,bytes,uint256,uint256,uint256,bytes32) message, bytes32[] leafProof, ((bytes32,uint256,bytes32,bytes32,(uint256,bytes4,bytes)[]),(uint256,uint256,bytes32[]),(uint8,uint32,bytes32,uint64,uint32,bytes32),bytes32[],uint256) headerProof) returns() +// Solidity: function submitInbound((bytes32,uint64,uint8,bytes,uint64,uint256,uint256,bytes32) message, bytes32[] leafProof, ((bytes32,uint256,bytes32,bytes32,(uint256,bytes4,bytes)[]),(uint256,uint256,bytes32[]),(uint8,uint32,bytes32,uint64,uint32,bytes32),bytes32[],uint256) headerProof) returns() func (_Gateway *GatewayTransactorSession) SubmitInbound(message InboundMessage, leafProof [][32]byte, headerProof VerificationProof) (*types.Transaction, error) { return _Gateway.Contract.SubmitInbound(&_Gateway.TransactOpts, message, leafProof, headerProof) } diff --git a/relayer/relays/parachain/scanner.go b/relayer/relays/parachain/scanner.go index 9d3e3cb9e9..b71687309d 100644 --- a/relayer/relays/parachain/scanner.go +++ b/relayer/relays/parachain/scanner.go @@ -1,8 +1,10 @@ package parachain import ( + "bytes" "context" "fmt" + "github.com/snowfork/go-substrate-rpc-client/v4/scale" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" @@ -185,12 +187,22 @@ func (s *Scanner) findTasksImpl( } var messages []OutboundQueueMessage - ok, err := s.paraConn.API().RPC.State.GetStorage(messagesKey, &messages, blockHash) + raw, err := s.paraConn.API().RPC.State.GetStorageRaw(messagesKey, blockHash) if err != nil { return nil, fmt.Errorf("fetch committed messages for block %v: %w", blockHash.Hex(), err) } - if !ok { - return nil, fmt.Errorf("committed messages not found for block %v", blockHash.Hex()) + decoder := scale.NewDecoder(bytes.NewReader(*raw)) + n, err := decoder.DecodeUintCompact() + if err != nil { + return nil, fmt.Errorf("decode message length error: %w", err) + } + for i := uint64(0); i < n.Uint64(); i++ { + m := OutboundQueueMessage{} + err = decoder.Decode(&m) + if err != nil { + return nil, fmt.Errorf("decode message error: %w", err) + } + messages = append(messages, m) } // For the outbound channel, the commitment hash is the merkle root of the messages diff --git a/relayer/relays/parachain/types.go b/relayer/relays/parachain/types.go index 4b8428c859..ef7ed6ef44 100644 --- a/relayer/relays/parachain/types.go +++ b/relayer/relays/parachain/types.go @@ -1,11 +1,12 @@ package parachain import ( + "github.com/snowfork/go-substrate-rpc-client/v4/scale" "github.com/snowfork/go-substrate-rpc-client/v4/types" "github.com/snowfork/snowbridge/relayer/chain/relaychain" "github.com/snowfork/snowbridge/relayer/contracts" "github.com/snowfork/snowbridge/relayer/crypto/merkle" - "github.com/vedhavyas/go-subkey/scale" + "math/big" ) // A Task contains the working state for message commitments in a single parachain block @@ -85,7 +86,7 @@ type OutboundQueueMessage struct { Nonce uint64 Command uint8 Params []byte - MaxDispatchGas types.U128 + MaxDispatchGas uint64 MaxRefund types.U128 Reward types.U128 ID types.Bytes32 @@ -97,13 +98,65 @@ func (m OutboundQueueMessage) IntoInboundMessage() contracts.InboundMessage { Nonce: m.Nonce, Command: m.Command, Params: m.Params, - MaxDispatchGas: m.MaxDispatchGas.Int, + MaxDispatchGas: m.MaxDispatchGas, MaxRefund: m.MaxRefund.Int, Reward: m.Reward.Int, Id: m.ID, } } +func (m OutboundQueueMessage) Encode(encoder scale.Encoder) error { + encoder.Encode(m.ChannelID) + encoder.EncodeUintCompact(*big.NewInt(0).SetUint64(m.Nonce)) + encoder.Encode(m.Command) + encoder.Encode(m.Params) + encoder.EncodeUintCompact(*big.NewInt(0).SetUint64(m.MaxDispatchGas)) + encoder.EncodeUintCompact(*m.MaxRefund.Int) + encoder.EncodeUintCompact(*m.Reward.Int) + encoder.Encode(m.ID) + return nil +} + +func (m *OutboundQueueMessage) Decode(decoder scale.Decoder) error { + err := decoder.Decode(&m.ChannelID) + if err != nil { + return err + } + decoded, err := decoder.DecodeUintCompact() + if err != nil { + return err + } + m.Nonce = decoded.Uint64() + err = decoder.Decode(&m.Command) + if err != nil { + return err + } + err = decoder.Decode(&m.Params) + if err != nil { + return err + } + decoded, err = decoder.DecodeUintCompact() + if err != nil { + return err + } + m.MaxDispatchGas = decoded.Uint64() + decoded, err = decoder.DecodeUintCompact() + if err != nil { + return err + } + m.MaxRefund = types.U128{Int: decoded} + decoded, err = decoder.DecodeUintCompact() + if err != nil { + return err + } + m.Reward = types.U128{Int: decoded} + err = decoder.Decode(&m.ID) + if err != nil { + return err + } + return nil +} + type MessageProof struct { Message OutboundQueueMessage Proof MerkleProof From 2c0110fc2a0ef46e9eec8e0142e1857cd1c09a1a Mon Sep 17 00:00:00 2001 From: ron Date: Tue, 28 Nov 2023 22:05:21 +0800 Subject: [PATCH 21/38] Increase SECONDS_PER_SLOT to 2 --- web/packages/test/scripts/deploy-ethereum.sh | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/web/packages/test/scripts/deploy-ethereum.sh b/web/packages/test/scripts/deploy-ethereum.sh index b52d297bfe..84f23f69c8 100755 --- a/web/packages/test/scripts/deploy-ethereum.sh +++ b/web/packages/test/scripts/deploy-ethereum.sh @@ -26,7 +26,7 @@ start_geth() { --trace "$ethereum_data_dir/trace" \ --gcmode archive \ --syncmode=full \ - > "$output_dir/geth.log" 2>&1 & + >"$output_dir/geth.log" 2>&1 & fi } @@ -63,23 +63,21 @@ start_lodestar() { --eth1=true \ --rest.namespace="*" \ --jwt-secret config/jwtsecret \ - > "$output_dir/lodestar.log" 2>&1 & + >"$output_dir/lodestar.log" 2>&1 & fi } -hack_beacon_client() -{ +hack_beacon_client() { echo "Hack lodestar for faster slot time" local preset_minimal_config_file="$web_dir/node_modules/.pnpm/@lodestar+config@$lodestar_version/node_modules/@lodestar/config/lib/chainConfig/presets/minimal.js" if [[ "$(uname)" == "Darwin" && -z "${IN_NIX_SHELL:-}" ]]; then - gsed -i "s/SECONDS_PER_SLOT: 6/SECONDS_PER_SLOT: 1/g" $preset_minimal_config_file + gsed -i "s/SECONDS_PER_SLOT: 6/SECONDS_PER_SLOT: 2/g" $preset_minimal_config_file else - sed -i "s/SECONDS_PER_SLOT: 6/SECONDS_PER_SLOT: 1/g" $preset_minimal_config_file + sed -i "s/SECONDS_PER_SLOT: 6/SECONDS_PER_SLOT: 2/g" $preset_minimal_config_file fi } -deploy_local() -{ +deploy_local() { # 1. deploy execution client echo "Starting execution node" start_geth @@ -88,7 +86,7 @@ deploy_local() sleep 3 if [ "$eth_fast_mode" == "true" ]; then - hack_beacon_client + hack_beacon_client fi # 2. deploy consensus client @@ -96,8 +94,7 @@ deploy_local() start_lodestar } -deploy_ethereum() -{ +deploy_ethereum() { check_tool && rm -rf "$ethereum_data_dir" && deploy_local } From dba9769c59af5652594507e60dd20f1a24aa019d Mon Sep 17 00:00:00 2001 From: ron Date: Tue, 28 Nov 2023 22:41:21 +0800 Subject: [PATCH 22/38] Merge main branch --- parachain/Cargo.lock | 21 ++++++--- parachain/pallets/outbound-queue/Cargo.toml | 6 +-- .../outbound-queue/src/benchmarking.rs | 4 +- parachain/pallets/outbound-queue/src/lib.rs | 2 +- .../outbound-queue/src/send_message_impl.rs | 4 +- parachain/pallets/outbound-queue/src/test.rs | 17 ++++---- parachain/runtime/tests/Cargo.toml | 3 ++ parachain/runtime/tests/src/lib.rs | 7 +-- parachain/runtime/tests/src/test_cases.rs | 6 +-- smoketest/.gitignore | 1 - smoketest/make-bindings.sh | 3 +- smoketest/src/constants.rs | 6 +-- smoketest/src/helper.rs | 43 ++++++------------- smoketest/src/parachains/mod.rs | 1 - smoketest/src/xcm.rs | 10 ++--- smoketest/tests/create_agent.rs | 2 +- smoketest/tests/create_channel.rs | 4 +- smoketest/tests/transfer_native_from_agent.rs | 2 +- web/packages/test/config/launch-config.toml | 23 +--------- web/packages/test/scripts/build-binary.sh | 5 +-- .../test/scripts/configure-bridgehub.sh | 6 +-- web/packages/test/scripts/set-env.sh | 9 ++-- web/packages/test/scripts/start-relayer.sh | 32 +++++++------- 23 files changed, 95 insertions(+), 122 deletions(-) diff --git a/parachain/Cargo.lock b/parachain/Cargo.lock index 2f6fcdddff..a6de042330 100644 --- a/parachain/Cargo.lock +++ b/parachain/Cargo.lock @@ -729,7 +729,6 @@ checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" dependencies = [ "funty", "radium", - "serde", "tap", "wyz", ] @@ -827,6 +826,20 @@ dependencies = [ "trie-db", ] +[[package]] +name = "bridge-hub-common" +version = "0.1.0" +dependencies = [ + "cumulus-primitives-core", + "frame-support", + "pallet-message-queue", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-std 8.0.0", + "staging-xcm", +] + [[package]] name = "bs58" version = "0.5.0" @@ -1527,7 +1540,7 @@ dependencies = [ [[package]] name = "ethabi-decode" version = "1.3.3" -source = "git+https://github.com/snowfork/ethabi-decode.git?branch=master#6f63405bb33ef4365a1c62b72d499fa0f448118e" +source = "git+https://github.com/Snowfork/ethabi-decode.git?branch=master#6f63405bb33ef4365a1c62b72d499fa0f448118e" dependencies = [ "ethereum-types", "tiny-keccak 1.5.0", @@ -1781,7 +1794,6 @@ name = "frame-system" version = "4.0.0-dev" dependencies = [ "cfg-if", - "docify", "frame-support", "log", "parity-scale-codec", @@ -2694,7 +2706,6 @@ dependencies = [ name = "pallet-message-queue" version = "7.0.0-dev" dependencies = [ - "environmental", "frame-benchmarking", "frame-support", "frame-system", @@ -3860,7 +3871,7 @@ dependencies = [ name = "snowbridge-outbound-queue" version = "0.1.1" dependencies = [ - "cumulus-primitives-core", + "bridge-hub-common", "ethabi-decode", "frame-benchmarking", "frame-support", diff --git a/parachain/pallets/outbound-queue/Cargo.toml b/parachain/pallets/outbound-queue/Cargo.toml index 2fdef01f1c..5706a955cb 100644 --- a/parachain/pallets/outbound-queue/Cargo.toml +++ b/parachain/pallets/outbound-queue/Cargo.toml @@ -24,7 +24,7 @@ sp-runtime = { path = "../../../polkadot-sdk/substrate/primitives/runtime", defa sp-io = { path = "../../../polkadot-sdk/substrate/primitives/io", default-features = false } sp-arithmetic = { path = "../../../polkadot-sdk/substrate/primitives/arithmetic", default-features = false } -cumulus-primitives-core = { path = "../../../polkadot-sdk/cumulus/primitives/core", default-features = false } +bridge-hub-common = { path = "../../../polkadot-sdk/cumulus/parachains/runtimes/bridge-hubs/common", default-features = false } snowbridge-core = { path = "../../primitives/core", features = ["serde"], default-features = false } snowbridge-outbound-queue-merkle-tree = { path = "merkle-tree", default-features = false } @@ -55,7 +55,7 @@ std = [ "snowbridge-outbound-queue-merkle-tree/std", "ethabi/std", "xcm/std", - "cumulus-primitives-core/std" + "bridge-hub-common/std", ] runtime-benchmarks = [ "snowbridge-core/runtime-benchmarks", @@ -63,5 +63,5 @@ runtime-benchmarks = [ "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "hex-literal", - "cumulus-primitives-core/runtime-benchmarks" + "bridge-hub-common/runtime-benchmarks", ] diff --git a/parachain/pallets/outbound-queue/src/benchmarking.rs b/parachain/pallets/outbound-queue/src/benchmarking.rs index 616737ef35..ee5754e869 100644 --- a/parachain/pallets/outbound-queue/src/benchmarking.rs +++ b/parachain/pallets/outbound-queue/src/benchmarking.rs @@ -2,8 +2,8 @@ // SPDX-FileCopyrightText: 2023 Snowfork use super::*; +use bridge_hub_common::AggregateMessageOrigin; use codec::Encode; -use cumulus_primitives_core::AggregateMessageOrigin; use frame_benchmarking::v2::*; use snowbridge_core::{ outbound::{Command, Initializer}, @@ -36,7 +36,7 @@ mod benchmarks { }), }, }; - let origin = AggregateMessageOrigin::GeneralKey([1; 32]); + let origin = AggregateMessageOrigin::Snowbridge([1; 32].into()); let encoded_enqueued_message = enqueued_message.encode(); #[block] diff --git a/parachain/pallets/outbound-queue/src/lib.rs b/parachain/pallets/outbound-queue/src/lib.rs index ff179e6176..86ca2f7ac9 100644 --- a/parachain/pallets/outbound-queue/src/lib.rs +++ b/parachain/pallets/outbound-queue/src/lib.rs @@ -92,8 +92,8 @@ mod mock; #[cfg(test)] mod test; +use bridge_hub_common::AggregateMessageOrigin; use codec::Decode; -use cumulus_primitives_core::AggregateMessageOrigin; use frame_support::{ storage::StorageStreamIter, traits::{tokens::Balance, Defensive, EnqueueMessage, Get, ProcessMessageError}, diff --git a/parachain/pallets/outbound-queue/src/send_message_impl.rs b/parachain/pallets/outbound-queue/src/send_message_impl.rs index f6c5188f94..e2bc32649b 100644 --- a/parachain/pallets/outbound-queue/src/send_message_impl.rs +++ b/parachain/pallets/outbound-queue/src/send_message_impl.rs @@ -1,7 +1,7 @@ //! Implementation for [`snowbridge_core::outbound::SendMessage`] use super::*; +use bridge_hub_common::AggregateMessageOrigin; use codec::Encode; -use cumulus_primitives_core::AggregateMessageOrigin; use frame_support::{ ensure, traits::{EnqueueMessage, Get}, @@ -72,7 +72,7 @@ where } fn deliver(ticket: Self::Ticket) -> Result { - let origin = AggregateMessageOrigin::GeneralKey(ticket.channel_id.into()); + let origin = AggregateMessageOrigin::Snowbridge(ticket.channel_id); if ticket.channel_id != PRIMARY_GOVERNANCE_CHANNEL { ensure!(!Self::operating_mode().is_halted(), SendError::Halted); diff --git a/parachain/pallets/outbound-queue/src/test.rs b/parachain/pallets/outbound-queue/src/test.rs index 1cf1f4b214..98e22c1101 100644 --- a/parachain/pallets/outbound-queue/src/test.rs +++ b/parachain/pallets/outbound-queue/src/test.rs @@ -76,7 +76,7 @@ fn process_message_yields_on_max_messages_per_block() { } let channel_id: ChannelId = ParaId::from(1000).into(); - let origin = AggregateMessageOrigin::GeneralKey(channel_id.into()); + let origin = AggregateMessageOrigin::Snowbridge(channel_id.into()); let message = QueuedMessage { id: Default::default(), channel_id, @@ -102,7 +102,7 @@ fn process_message_fails_on_overweight_message() { new_tester().execute_with(|| { let sibling_id = 1000; let channel_id: ChannelId = ParaId::from(sibling_id).into(); - let origin = AggregateMessageOrigin::GeneralKey(channel_id.into()); + let origin = AggregateMessageOrigin::Snowbridge(channel_id.into()); let message = mock_message(sibling_id).encode(); let mut meter = WeightMeter::with_limit(Weight::from_parts(1, 1)); assert_noop!( @@ -152,7 +152,8 @@ fn governance_message_does_not_get_the_chance_to_processed_in_same_block_when_co let (ticket, _) = OutboundQueue::validate(&message).unwrap(); OutboundQueue::deliver(ticket).unwrap(); } - let footprint = MessageQueue::footprint(GeneralKey(sibling_channel_id.into())); + + let footprint = MessageQueue::footprint(Snowbridge(sibling_channel_id.into())); assert_eq!(footprint.storage.count, (max_messages) as u64); let message = mock_governance_message::(); @@ -164,11 +165,11 @@ fn governance_message_does_not_get_the_chance_to_processed_in_same_block_when_co run_to_end_of_next_block(); // first process 20 messages from sibling channel - let footprint = MessageQueue::footprint(GeneralKey(sibling_channel_id.into())); + let footprint = MessageQueue::footprint(Snowbridge(sibling_channel_id.into())); assert_eq!(footprint.storage.count, 40 - 20); // and governance message does not have the chance to execute in same block - let footprint = MessageQueue::footprint(GeneralKey(PRIMARY_GOVERNANCE_CHANNEL.into())); + let footprint = MessageQueue::footprint(Snowbridge(PRIMARY_GOVERNANCE_CHANNEL.into())); assert_eq!(footprint.storage.count, 1); // move to next block @@ -176,17 +177,17 @@ fn governance_message_does_not_get_the_chance_to_processed_in_same_block_when_co run_to_end_of_next_block(); // now governance message get executed in this block - let footprint = MessageQueue::footprint(GeneralKey(PRIMARY_GOVERNANCE_CHANNEL.into())); + let footprint = MessageQueue::footprint(Snowbridge(PRIMARY_GOVERNANCE_CHANNEL.into())); assert_eq!(footprint.storage.count, 0); // and this time process 19 messages from sibling channel so we have 1 message left - let footprint = MessageQueue::footprint(GeneralKey(sibling_channel_id.into())); + let footprint = MessageQueue::footprint(Snowbridge(sibling_channel_id.into())); assert_eq!(footprint.storage.count, 1); // move to the next block, the last 1 message from sibling channel get executed ServiceWeight::set(Some(Weight::MAX)); run_to_end_of_next_block(); - let footprint = MessageQueue::footprint(GeneralKey(sibling_channel_id.into())); + let footprint = MessageQueue::footprint(Snowbridge(sibling_channel_id.into())); assert_eq!(footprint.storage.count, 0); }); } diff --git a/parachain/runtime/tests/Cargo.toml b/parachain/runtime/tests/Cargo.toml index ede65f7b03..1615cb30dd 100644 --- a/parachain/runtime/tests/Cargo.toml +++ b/parachain/runtime/tests/Cargo.toml @@ -72,6 +72,7 @@ parachain-info = { package = "staging-parachain-info", path = "../../../polkadot parachains-common = { path = "../../../polkadot-sdk/cumulus/parachains/common", default-features = false } parachains-runtimes-test-utils = { path = "../../../polkadot-sdk/cumulus/parachains/runtimes/test-utils", default-features = false } bridge-hub-rococo-runtime = { path = "../../../polkadot-sdk/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo", default-features = false } +asset-hub-rococo-runtime = { path = "../../../polkadot-sdk/cumulus/parachains/runtimes/assets/asset-hub-rococo", default-features = false } assets-common = { path = "../../../polkadot-sdk/cumulus/parachains/runtimes/assets/common", default-features = false } # Ethereum Bridge (Snowbridge) @@ -104,6 +105,7 @@ std = [ "cumulus-primitives-core/std", "cumulus-primitives-utility/std", "bridge-hub-rococo-runtime/std", + "asset-hub-rococo-runtime/std", "assets-common/std", "parachains-runtimes-test-utils/std", "frame-benchmarking/std", @@ -169,6 +171,7 @@ runtime-benchmarks = [ "cumulus-pallet-xcmp-queue/runtime-benchmarks", "cumulus-primitives-utility/runtime-benchmarks", "bridge-hub-rococo-runtime/runtime-benchmarks", + "asset-hub-rococo-runtime/runtime-benchmarks", "assets-common/runtime-benchmarks", "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", diff --git a/parachain/runtime/tests/src/lib.rs b/parachain/runtime/tests/src/lib.rs index 8b5e9b18b7..1132160feb 100644 --- a/parachain/runtime/tests/src/lib.rs +++ b/parachain/runtime/tests/src/lib.rs @@ -7,7 +7,8 @@ mod test_cases; use bridge_hub_rococo_runtime::{xcm_config::XcmConfig, Runtime, RuntimeEvent, SessionKeys}; use codec::Decode; -use parachains_common::{snowbridge_config::BridgeHubEthereumBaseFeeInRocs, AccountId, AuraId}; +use parachains_common::{AccountId, AuraId}; +use asset_hub_rococo_runtime::xcm_config::bridging::to_ethereum::BridgeHubEthereumBaseFeeInROC; use sp_core::H160; use sp_keyring::AccountKeyring::Alice; @@ -27,7 +28,7 @@ pub fn transfer_token_to_ethereum_works() { 1000, H160::random(), H160::random(), - BridgeHubEthereumBaseFeeInRocs::get(), + BridgeHubEthereumBaseFeeInROC::get(), Box::new(|runtime_event_encoded: Vec| { match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { Ok(RuntimeEvent::EthereumOutboundQueue(event)) => Some(event), @@ -69,6 +70,6 @@ pub fn transfer_token_to_ethereum_insufficient_fund() { 1000, H160::random(), H160::random(), - BridgeHubEthereumBaseFeeInRocs::get(), + BridgeHubEthereumBaseFeeInROC::get(), ) } diff --git a/parachain/runtime/tests/src/test_cases.rs b/parachain/runtime/tests/src/test_cases.rs index 01a039902c..7bea8477ac 100644 --- a/parachain/runtime/tests/src/test_cases.rs +++ b/parachain/runtime/tests/src/test_cases.rs @@ -5,7 +5,7 @@ use codec::Encode; use frame_support::{assert_err, assert_ok, traits::fungible::Mutate}; -use parachains_common::snowbridge_config::BridgeHubEthereumBaseFeeInRocs; +use asset_hub_rococo_runtime::xcm_config::bridging::to_ethereum::BridgeHubEthereumBaseFeeInROC; use parachains_runtimes_test_utils::{ AccountIdOf, BalanceOf, CollatorSessionKeys, ExtBuilder, ValidatorIdOf, XcmReceivedFrom, }; @@ -131,7 +131,7 @@ pub fn send_transfer_token_message_success( // fund asset hub sovereign account enough so it can pay fees initial_fund::( assethub_parachain_id, - BridgeHubEthereumBaseFeeInRocs::get() + 1_000_000_000, + BridgeHubEthereumBaseFeeInROC::get() + 1_000_000_000, ); let outcome = send_transfer_token_message::( @@ -269,7 +269,7 @@ pub fn send_transfer_token_message_fee_not_enough( // fund asset hub sovereign account enough so it can pay fees initial_fund::( assethub_parachain_id, - BridgeHubEthereumBaseFeeInRocs::get() + 1_000_000_000, + BridgeHubEthereumBaseFeeInROC::get() + 1_000_000_000, ); let outcome = send_transfer_token_message::( diff --git a/smoketest/.gitignore b/smoketest/.gitignore index 5a6a269397..e40652197b 100644 --- a/smoketest/.gitignore +++ b/smoketest/.gitignore @@ -15,5 +15,4 @@ src/parachains/assethub.rs src/parachains/bridgehub.rs src/parachains/penpal.rs src/parachains/relaychain.rs -src/parachains/template.rs src/contracts diff --git a/smoketest/make-bindings.sh b/smoketest/make-bindings.sh index aceb1a716c..d70dc0cb6e 100755 --- a/smoketest/make-bindings.sh +++ b/smoketest/make-bindings.sh @@ -23,6 +23,5 @@ fi # Fetch metadata from BridgeHub and generate client subxt codegen --url ws://localhost:11144 > src/parachains/bridgehub.rs subxt codegen --url ws://localhost:12144 > src/parachains/assethub.rs -subxt codegen --url ws://localhost:13144 > src/parachains/template.rs -subxt codegen --url ws://localhost:14144 > src/parachains/penpal.rs +subxt codegen --url ws://localhost:13144 > src/parachains/penpal.rs subxt codegen --url ws://localhost:9944 > src/parachains/relaychain.rs diff --git a/smoketest/src/constants.rs b/smoketest/src/constants.rs index 5263c9f80c..0c2ed43cb9 100644 --- a/smoketest/src/constants.rs +++ b/smoketest/src/constants.rs @@ -10,7 +10,7 @@ pub const ETHEREUM_HTTP_API: &str = "http://localhost:8545"; pub const ASSET_HUB_WS_URL: &str = "ws://127.0.0.1:12144"; pub const BRIDGE_HUB_WS_URL: &str = "ws://127.0.0.1:11144"; -pub const PENPAL_WS_URL: &str = "ws://127.0.0.1:14144"; +pub const PENPAL_WS_URL: &str = "ws://127.0.0.1:13144"; pub const RELAY_CHAIN_WS_URL: &str = "ws://127.0.0.1:9944"; pub const TEMPLATE_NODE_WS_URL: &str = "ws://127.0.0.1:13144"; @@ -29,9 +29,9 @@ pub const BRIDGE_HUB_AGENT_ID: [u8; 32] = // Agent for asset hub parachain 1000 pub const ASSET_HUB_AGENT_ID: [u8; 32] = hex!("72456f48efed08af20e5b317abf8648ac66e86bb90a411d9b0b713f7364b75b4"); -// Agent for template parachain 1001 +// Agent for penpal parachain 2000 pub const SIBLING_AGENT_ID: [u8; 32] = - hex!("e01018a3378502770faff44fbef3910d120a0353d18be653625b8daa88a86453"); + hex!("5097ee1101e90c3aadb882858c59a22108668021ec81bce9f4930155e5c21e59"); pub const ASSET_HUB_SOVEREIGN: [u8; 32] = hex!("7369626ce8030000000000000000000000000000000000000000000000000000"); diff --git a/smoketest/src/helper.rs b/smoketest/src/helper.rs index f2f1f53979..252609dac8 100644 --- a/smoketest/src/helper.rs +++ b/smoketest/src/helper.rs @@ -31,8 +31,8 @@ use crate::{ VersionedXcm as RelaychainVersionedXcm, }, }, - template::{ - api::runtime_types as templateTypes, + penpal::{ + api::runtime_types as penpalTypes, {self}, }, }, @@ -54,28 +54,16 @@ use subxt::{ tx::{PairSigner, TxPayload}, Config, OnlineClient, PolkadotConfig, SubstrateConfig, }; -use templateTypes::{ +use penpalTypes::{ staging_xcm::v3::multilocation::MultiLocation, xcm::{ v3::{junction::Junction, junctions::Junctions}, VersionedMultiLocation, VersionedXcm, }, + pallet_xcm::pallet::Call, + penpal_runtime::RuntimeCall }; -/// Custom config that works with TemplateParachain -pub enum TemplateConfig {} - -impl Config for TemplateConfig { - type Index = ::Index; - type Hash = ::Hash; - type AccountId = ::AccountId; - type Address = ::Address; - type Signature = ::Signature; - type Hasher = ::Hasher; - type Header = ::Header; - type ExtrinsicParams = ::ExtrinsicParams; -} - /// Custom config that works with Penpal pub enum PenpalConfig {} @@ -107,7 +95,6 @@ impl Config for AssetHubConfig { pub struct TestClients { pub asset_hub_client: Box>, pub bridge_hub_client: Box>, - pub template_client: Box>, pub penpal_client: Box>, pub relaychain_client: Box>, pub ethereum_client: Box>>, @@ -123,11 +110,6 @@ pub async fn initial_clients() -> Result .await .expect("can not connect to bridgehub"); - let template_client: OnlineClient = - OnlineClient::from_url(TEMPLATE_NODE_WS_URL) - .await - .expect("can not connect to template parachain"); - let penpal_client: OnlineClient = OnlineClient::from_url(PENPAL_WS_URL) .await .expect("can not connect to penpal parachain"); @@ -149,7 +131,6 @@ pub async fn initial_clients() -> Result Ok(TestClients { asset_hub_client: Box::new(asset_hub_client), bridge_hub_client: Box::new(bridge_hub_client), - template_client: Box::new(template_client), penpal_client: Box::new(penpal_client), relaychain_client: Box::new(relaychain_client), ethereum_client: Box::new(ethereum_client), @@ -208,24 +189,24 @@ pub async fn wait_for_ethereum_event(ethereum_client: &Box>, +pub async fn send_sudo_xcm_transact( + penpal_client: &Box>, message: Box, -) -> Result, Box> { +) -> Result, Box> { let dest = Box::new(VersionedMultiLocation::V3(MultiLocation { parents: 1, interior: Junctions::X1(Junction::Parachain(BRIDGE_HUB_PARA_ID)), })); - let xcm_call = template::api::template_pallet::calls::TransactionApi.send_xcm(*dest, *message); + let sudo_call = penpal::api::sudo::calls::TransactionApi::sudo(&penpal::api::sudo::calls::TransactionApi,RuntimeCall::PolkadotXcm(Call::send { dest, message })); let owner: Pair = Pair::from_string("//Alice", None).expect("cannot create keypair"); - let signer: PairSigner = PairSigner::new(owner); + let signer: PairSigner = PairSigner::new(owner); - let result = template_client + let result = penpal_client .tx() - .sign_and_submit_then_watch_default(&xcm_call, &signer) + .sign_and_submit_then_watch_default(&sudo_call, &signer) .await .expect("send through xcm call.") .wait_for_finalized_success() diff --git a/smoketest/src/parachains/mod.rs b/smoketest/src/parachains/mod.rs index b1195f1820..acadad41d9 100644 --- a/smoketest/src/parachains/mod.rs +++ b/smoketest/src/parachains/mod.rs @@ -2,4 +2,3 @@ pub mod assethub; pub mod bridgehub; pub mod penpal; pub mod relaychain; -pub mod template; diff --git a/smoketest/src/xcm.rs b/smoketest/src/xcm.rs index 1efea9d698..70785456a4 100644 --- a/smoketest/src/xcm.rs +++ b/smoketest/src/xcm.rs @@ -1,10 +1,10 @@ -use crate::parachains::template::api::{ - runtime_types as templateTypes, runtime_types::staging_xcm as templateXcm, +use crate::parachains::penpal::api::{ + runtime_types as penpalTypes, runtime_types::staging_xcm as penpalXcm, }; -use templateTypes::sp_weights::weight_v2::Weight; -use templateXcm::v3::multilocation::MultiLocation; +use penpalTypes::sp_weights::weight_v2::Weight; +use penpalXcm::v3::multilocation::MultiLocation; -use templateTypes::xcm::{ +use penpalTypes::xcm::{ double_encoded::DoubleEncoded, v2::OriginKind, v3::{ diff --git a/smoketest/tests/create_agent.rs b/smoketest/tests/create_agent.rs index e68ecd2784..ffefd28fff 100644 --- a/smoketest/tests/create_agent.rs +++ b/smoketest/tests/create_agent.rs @@ -14,7 +14,7 @@ async fn create_agent() { let message = construct_xcm_message_with_fee(encoded_call).await; - let result = send_xcm_transact(&test_clients.template_client, message) + let result = send_sudo_xcm_transact(&test_clients.penpal_client, message) .await .expect("failed to send xcm transact."); diff --git a/smoketest/tests/create_channel.rs b/smoketest/tests/create_channel.rs index e4f2f4f449..6689950969 100644 --- a/smoketest/tests/create_channel.rs +++ b/smoketest/tests/create_channel.rs @@ -10,11 +10,11 @@ async fn create_channel() { let encoded_call = construct_create_channel_call(&test_clients.bridge_hub_client) .await - .expect("construct innner call."); + .expect("construct inner call."); let message = construct_xcm_message_with_fee(encoded_call).await; - let result = send_xcm_transact(&test_clients.template_client, message) + let result = send_sudo_xcm_transact(&test_clients.penpal_client, message) .await .expect("failed to send xcm transact."); diff --git a/smoketest/tests/transfer_native_from_agent.rs b/smoketest/tests/transfer_native_from_agent.rs index 99e082ce97..8c78cc4c32 100644 --- a/smoketest/tests/transfer_native_from_agent.rs +++ b/smoketest/tests/transfer_native_from_agent.rs @@ -41,7 +41,7 @@ async fn transfer_native_from_agent() { ) .await; - let result = send_xcm_transact(&test_clients.template_client, message) + let result = send_sudo_xcm_transact(&test_clients.penpal_client, message) .await .expect("failed to send xcm transact."); diff --git a/web/packages/test/config/launch-config.toml b/web/packages/test/config/launch-config.toml index 6751e27d7c..4920e4c4f2 100644 --- a/web/packages/test/config/launch-config.toml +++ b/web/packages/test/config/launch-config.toml @@ -70,25 +70,6 @@ cumulus_based = true "-lparachain=debug,xcm=trace,runtime::bridge-assets-transfer=trace,runtime::assets=trace,runtime::bridge-transfer=trace", ] - -## Template node -[[parachains]] -id = 1001 -chain = "template-rococo" -cumulus_based = true - - # run alice as parachain collator - [[parachains.collators]] - name = "template01" - validator = true - command = "{{output_bin_dir}}/parachain-template-node" - rpc_port = 8083 - ws_port = 13144 - args = [ - "--force-authoring", - "-lparachain=debug,xcm=trace,runtime::bridge-assets-transfer=trace,runtime::assets=trace,runtime::bridge-transfer=trace", - ] - ## Penpal [[parachains]] id = 2000 @@ -100,8 +81,8 @@ cumulus_based = true validator = true command = "{{output_bin_dir}}/polkadot-parachain" rpc_port = 8084 - ws_port = 14144 - args = [ + ws_port = 13144 + args = [ "--force-authoring", "-lxcm=trace,runtime::assets=trace", ] diff --git a/web/packages/test/scripts/build-binary.sh b/web/packages/test/scripts/build-binary.sh index 7984d330ce..d8355c2053 100755 --- a/web/packages/test/scripts/build-binary.sh +++ b/web/packages/test/scripts/build-binary.sh @@ -11,12 +11,11 @@ build_binaries() { features=--features beacon-spec-mainnet fi - echo "Building polkadot binary and parachain template node" - cargo build --release --workspace --locked --bin polkadot --bin polkadot-execute-worker --bin polkadot-prepare-worker --bin parachain-template-node + echo "Building polkadot binary" + cargo build --release --workspace --locked --bin polkadot --bin polkadot-execute-worker --bin polkadot-prepare-worker cp target/release/polkadot $output_bin_dir/polkadot cp target/release/polkadot-execute-worker $output_bin_dir/polkadot-execute-worker cp target/release/polkadot-prepare-worker $output_bin_dir/polkadot-prepare-worker - cp target/release/parachain-template-node $output_bin_dir/parachain-template-node echo "Building polkadot-parachain binary" cargo build --release --workspace --locked --bin polkadot-parachain $features diff --git a/web/packages/test/scripts/configure-bridgehub.sh b/web/packages/test/scripts/configure-bridgehub.sh index 73001cff7e..a8c2260b85 100755 --- a/web/packages/test/scripts/configure-bridgehub.sh +++ b/web/packages/test/scripts/configure-bridgehub.sh @@ -24,7 +24,7 @@ wait_beacon_chain_ready() { fund_accounts() { echo "Funding substrate accounts" transfer_balance $relaychain_ws_url "//Charlie" 1013 1000000000000000 $assethub_sovereign_account - transfer_balance $relaychain_ws_url "//Charlie" 1013 1000000000000000 $template_sovereign_account + transfer_balance $relaychain_ws_url "//Charlie" 1013 1000000000000000 $penpal_sovereign_account transfer_balance $relaychain_ws_url "//Charlie" 1013 1000000000000000 $beacon_relayer_pub_key transfer_balance $relaychain_ws_url "//Charlie" 1013 1000000000000000 $execution_relayer_pub_key } @@ -63,8 +63,8 @@ open_hrmp_channels() echo "Opening HRMP channels" open_hrmp_channel "${relaychain_ws_url}" "${relaychain_sudo_seed}" 1000 1013 8 512 # Assethub -> BridgeHub open_hrmp_channel "${relaychain_ws_url}" "${relaychain_sudo_seed}" 1013 1000 8 512 # BridgeHub -> Assethub - open_hrmp_channel "${relaychain_ws_url}" "${relaychain_sudo_seed}" 1001 1013 8 512 # TemplateNode -> BridgeHub - open_hrmp_channel "${relaychain_ws_url}" "${relaychain_sudo_seed}" 1013 1001 8 512 # BridgeHub -> TemplateNode + open_hrmp_channel "${relaychain_ws_url}" "${relaychain_sudo_seed}" 2000 1013 8 512 # Penpal -> BridgeHub + open_hrmp_channel "${relaychain_ws_url}" "${relaychain_sudo_seed}" 1013 2000 8 512 # BridgeHub -> Penpal open_hrmp_channel "${relaychain_ws_url}" "${relaychain_sudo_seed}" 1000 2000 8 512 # Penpal -> AssetHub open_hrmp_channel "${relaychain_ws_url}" "${relaychain_sudo_seed}" 2000 1000 8 512 # Assethub -> Penpal } diff --git a/web/packages/test/scripts/set-env.sh b/web/packages/test/scripts/set-env.sh index 0451baf09f..315eea26fe 100755 --- a/web/packages/test/scripts/set-env.sh +++ b/web/packages/test/scripts/set-env.sh @@ -42,11 +42,9 @@ 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:-0x72456f48efed08af20e5b317abf8648ac66e86bb90a411d9b0b713f7364b75b4}" -export TEMPLATE_PARA_ID="${TEMPLATE_PARA_ID:-1001}" -export TEMPLATE_AGENT_ID="${TEMPLATE_AGENT_ID:-0x2075b9f5bc236462eb1473c9a6236c3588e33ed19ead53aa3d9c62ed941cb793}" export ASSET_HUB_CHANNEL_ID="0xc173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539" -export TEMPLATE_CHANNEL_ID="0x26c13363ad6499b895574b3ca482545dda41d657ffc5673b39a218cd34053e5b" +export PENPAL_CHANNEL_ID="0xa69fbbae90bb6096d59b1930bbcfc8a3ef23959d226b1861deb7ad8fb06c6fa3" export PRIMARY_GOVERNANCE_CHANNEL_ID="0x0000000000000000000000000000000000000000000000000000000000000001" export SECONDARY_GOVERNANCE_CHANNEL_ID="0x0000000000000000000000000000000000000000000000000000000000000002" @@ -61,10 +59,11 @@ skip_relayer="${SKIP_RELAYER:-false}" ## Important accounts +# Useful tool to get these account values: https://www.shawntabrizi.com/substrate-js-utilities/ # Account for assethub (Sibling parachain 1000 5Eg2fntNprdN3FgH4sfEaaZhYtddZQSQUqvYJ1f2mLtinVhV in testnet) assethub_sovereign_account="${ASSETHUB_SOVEREIGN_ACCOUNT:-0x7369626ce8030000000000000000000000000000000000000000000000000000}" -# Account for template (Sibling parachain 1001 5Eg2fntP2UgYZNc5tW8xmmCmeXJ3hmNXaZ9MvcpbMdvh1bBJ in testnet) -template_sovereign_account="${TEMPLATE_SOVEREIGN_ACCOUNT:-0x7369626ce9030000000000000000000000000000000000000000000000000000}" +# Account for penpal (Sibling parachain 2000 5Eg2fntJ27qsari4FGrGhrMqKFDRnkNSR6UshkZYBGXmSuC8 in testnet) +penpal_sovereign_account="${PENPAL_SOVEREIGN_ACCOUNT:-0x7369626cd0070000000000000000000000000000000000000000000000000000}" # Beacon relay account (//BeaconRelay 5GWFwdZb6JyU46e6ZiLxjGxogAHe8SenX76btfq8vGNAaq8c in testnet) beacon_relayer_pub_key="${BEACON_RELAYER_PUB_KEY:-0xc46e141b5083721ad5f5056ba1cded69dce4a65f027ed3362357605b1687986a}" # Execution relay account (//ExecutionRelay 5CFNWKMFPsw5Cs2Teo6Pvg7rWyjKiFfqPZs8U4MZXzMYFwXL in testnet) diff --git a/web/packages/test/scripts/start-relayer.sh b/web/packages/test/scripts/start-relayer.sh index 23c27fcfe0..d5a0bf0bfe 100755 --- a/web/packages/test/scripts/start-relayer.sh +++ b/web/packages/test/scripts/start-relayer.sh @@ -71,12 +71,12 @@ config_relayer() { ' \ config/parachain-relay.json >$output_dir/parachain-relay-asset-hub.json - # Configure parachain relay (parachain template) + # Configure parachain relay (penpal) jq \ --arg k1 "$(address_for GatewayProxy)" \ --arg k2 "$(address_for BeefyClient)" \ --arg eth_endpoint_ws $eth_endpoint_ws \ - --arg channelID $TEMPLATE_CHANNEL_ID \ + --arg channelID $PENPAL_CHANNEL_ID \ --arg eth_gas_limit $eth_gas_limit \ ' .source.contracts.Gateway = $k1 @@ -87,7 +87,7 @@ config_relayer() { | .sink.ethereum."gas-limit" = $eth_gas_limit | .source."channel-id" = $channelID ' \ - config/parachain-relay.json >$output_dir/parachain-relay-template.json + config/parachain-relay.json >$output_dir/parachain-relay-penpal.json # Configure beacon relay jq \ @@ -111,17 +111,17 @@ config_relayer() { ' \ config/execution-relay.json >$output_dir/execution-relay-asset-hub.json - # Configure execution relay for template node + # Configure execution relay for penpal jq \ --arg eth_endpoint_ws $eth_endpoint_ws \ --arg k1 "$(address_for GatewayProxy)" \ - --arg channelID $TEMPLATE_CHANNEL_ID \ + --arg channelID $PENPAL_CHANNEL_ID \ ' .source.ethereum.endpoint = $eth_endpoint_ws | .source.contracts.Gateway = $k1 | .source."channel-id" = $channelID ' \ - config/execution-relay.json >$output_dir/execution-relay-template.json + config/execution-relay.json >$output_dir/execution-relay-penpal.json } start_relayer() { @@ -178,15 +178,15 @@ start_relayer() { done ) & - # Launch parachain relay for parachain template + # Launch parachain relay for parachain penpal ( - : >"$output_dir"/parachain-relay-template.log + : >"$output_dir"/parachain-relay-penpal.log while :; do - echo "Starting parachain-relay (parachain-template) at $(date)" + echo "Starting parachain-relay (penpal) at $(date)" "${relay_bin}" run parachain \ - --config "$output_dir/parachain-relay-template.json" \ + --config "$output_dir/parachain-relay-penpal.json" \ --ethereum.private-key $parachain_relay_eth_key \ - >>"$output_dir"/parachain-relay-template.log 2>&1 || true + >>"$output_dir"/parachain-relay-penpal.log 2>&1 || true sleep 20 done ) & @@ -217,15 +217,15 @@ start_relayer() { done ) & - # Launch execution relay for template + # Launch execution relay for penpal ( - : >$output_dir/execution-relay-template.log + : >$output_dir/execution-relay-penpal.log while :; do - echo "Starting execution relay (parachain-template) at $(date)" + echo "Starting execution relay (penpal) at $(date)" "${relay_bin}" run execution \ - --config $output_dir/execution-relay-template.json \ + --config $output_dir/execution-relay-penpal.json \ --substrate.private-key "//ExecutionRelay" \ - >>"$output_dir"/execution-relay-template.log 2>&1 || true + >>"$output_dir"/execution-relay-penpal.log 2>&1 || true sleep 20 done ) & From a4a62a5348ac67b30bb9828d9f58daba6b485fa2 Mon Sep 17 00:00:00 2001 From: ron Date: Tue, 28 Nov 2023 22:43:26 +0800 Subject: [PATCH 23/38] Update sdk --- parachain/Cargo.lock | 6 +++++- polkadot-sdk | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/parachain/Cargo.lock b/parachain/Cargo.lock index a6de042330..9066fd8a12 100644 --- a/parachain/Cargo.lock +++ b/parachain/Cargo.lock @@ -729,6 +729,7 @@ checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" dependencies = [ "funty", "radium", + "serde", "tap", "wyz", ] @@ -835,6 +836,7 @@ dependencies = [ "pallet-message-queue", "parity-scale-codec", "scale-info", + "snowbridge-core", "sp-runtime", "sp-std 8.0.0", "staging-xcm", @@ -1540,7 +1542,7 @@ dependencies = [ [[package]] name = "ethabi-decode" version = "1.3.3" -source = "git+https://github.com/Snowfork/ethabi-decode.git?branch=master#6f63405bb33ef4365a1c62b72d499fa0f448118e" +source = "git+https://github.com/snowfork/ethabi-decode.git?branch=master#6f63405bb33ef4365a1c62b72d499fa0f448118e" dependencies = [ "ethereum-types", "tiny-keccak 1.5.0", @@ -1794,6 +1796,7 @@ name = "frame-system" version = "4.0.0-dev" dependencies = [ "cfg-if", + "docify", "frame-support", "log", "parity-scale-codec", @@ -2706,6 +2709,7 @@ dependencies = [ name = "pallet-message-queue" version = "7.0.0-dev" dependencies = [ + "environmental", "frame-benchmarking", "frame-support", "frame-system", diff --git a/polkadot-sdk b/polkadot-sdk index ec3368061c..2fc82bea16 160000 --- a/polkadot-sdk +++ b/polkadot-sdk @@ -1 +1 @@ -Subproject commit ec3368061c1e4a9a4b05da6202ef59516a75abd3 +Subproject commit 2fc82bea16d8dadae925dd84a5b54b1507af90bc From 5b65043a82a63019a9e6cd053a256e50e33ccfec Mon Sep 17 00:00:00 2001 From: ron Date: Tue, 28 Nov 2023 23:43:28 +0800 Subject: [PATCH 24/38] Update sdk --- parachain/runtime/tests/Cargo.lock | 868 +++++++++++++++++++++++------ polkadot-sdk | 2 +- 2 files changed, 685 insertions(+), 185 deletions(-) diff --git a/parachain/runtime/tests/Cargo.lock b/parachain/runtime/tests/Cargo.lock index 0227aa1339..d30c34a41f 100644 --- a/parachain/runtime/tests/Cargo.lock +++ b/parachain/runtime/tests/Cargo.lock @@ -385,6 +385,18 @@ dependencies = [ "ark-std 0.4.0", ] +[[package]] +name = "ark-bls12-377-ext" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20c7021f180a0cbea0380eba97c2af3c57074cdaffe0eef7e840e1c9f2841e55" +dependencies = [ + "ark-bls12-377", + "ark-ec", + "ark-models-ext", + "ark-std 0.4.0", +] + [[package]] name = "ark-bls12-381" version = "0.4.0" @@ -397,6 +409,45 @@ dependencies = [ "ark-std 0.4.0", ] +[[package]] +name = "ark-bls12-381-ext" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1dc4b3d08f19e8ec06e949712f95b8361e43f1391d94f65e4234df03480631c" +dependencies = [ + "ark-bls12-381", + "ark-ec", + "ark-ff 0.4.2", + "ark-models-ext", + "ark-serialize 0.4.2", + "ark-std 0.4.0", +] + +[[package]] +name = "ark-bw6-761" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e0605daf0cc5aa2034b78d008aaf159f56901d92a52ee4f6ecdfdac4f426700" +dependencies = [ + "ark-bls12-377", + "ark-ec", + "ark-ff 0.4.2", + "ark-std 0.4.0", +] + +[[package]] +name = "ark-bw6-761-ext" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccee5fba47266f460067588ee1bf070a9c760bf2050c1c509982c5719aadb4f2" +dependencies = [ + "ark-bw6-761", + "ark-ec", + "ark-ff 0.4.2", + "ark-models-ext", + "ark-std 0.4.0", +] + [[package]] name = "ark-ec" version = "0.4.2" @@ -411,9 +462,35 @@ dependencies = [ "hashbrown 0.13.2", "itertools 0.10.5", "num-traits", + "rayon", "zeroize", ] +[[package]] +name = "ark-ed-on-bls12-377" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b10d901b9ac4b38f9c32beacedfadcdd64e46f8d7f8e88c1ae1060022cf6f6c6" +dependencies = [ + "ark-bls12-377", + "ark-ec", + "ark-ff 0.4.2", + "ark-std 0.4.0", +] + +[[package]] +name = "ark-ed-on-bls12-377-ext" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524a4fb7540df2e1a8c2e67a83ba1d1e6c3947f4f9342cc2359fc2e789ad731d" +dependencies = [ + "ark-ec", + "ark-ed-on-bls12-377", + "ark-ff 0.4.2", + "ark-models-ext", + "ark-std 0.4.0", +] + [[package]] name = "ark-ed-on-bls12-381-bandersnatch" version = "0.4.0" @@ -426,6 +503,19 @@ dependencies = [ "ark-std 0.4.0", ] +[[package]] +name = "ark-ed-on-bls12-381-bandersnatch-ext" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d15185f1acb49a07ff8cbe5f11a1adc5a93b19e211e325d826ae98e98e124346" +dependencies = [ + "ark-ec", + "ark-ed-on-bls12-381-bandersnatch", + "ark-ff 0.4.2", + "ark-models-ext", + "ark-std 0.4.0", +] + [[package]] name = "ark-ff" version = "0.3.0" @@ -509,6 +599,19 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ark-models-ext" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e9eab5d4b5ff2f228b763d38442adc9b084b0a465409b059fac5c2308835ec2" +dependencies = [ + "ark-ec", + "ark-ff 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", +] + [[package]] name = "ark-poly" version = "0.4.2" @@ -539,7 +642,7 @@ dependencies = [ [[package]] name = "ark-secret-scalar" version = "0.0.2" -source = "git+https://github.com/w3f/ring-vrf?rev=4b09416#4b09416fd23383ec436ddac127d58c7b7cd392c6" +source = "git+https://github.com/w3f/ring-vrf?rev=cbc342e#cbc342e95d3cbcd3c5ba8d45af7200eb58e63502" dependencies = [ "ark-ec", "ark-ff 0.4.2", @@ -602,12 +705,13 @@ checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" dependencies = [ "num-traits", "rand 0.8.5", + "rayon", ] [[package]] name = "ark-transcript" version = "0.0.2" -source = "git+https://github.com/w3f/ring-vrf?rev=4b09416#4b09416fd23383ec436ddac127d58c7b7cd392c6" +source = "git+https://github.com/w3f/ring-vrf?rev=cbc342e#cbc342e95d3cbcd3c5ba8d45af7200eb58e63502" dependencies = [ "ark-ff 0.4.2", "ark-serialize 0.4.2", @@ -714,12 +818,91 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "asset-hub-rococo-runtime" +version = "0.9.420" +dependencies = [ + "assets-common", + "bp-asset-hub-rococo", + "bp-asset-hub-westend", + "bp-bridge-hub-rococo", + "bp-bridge-hub-westend", + "cumulus-pallet-aura-ext", + "cumulus-pallet-dmp-queue", + "cumulus-pallet-parachain-system", + "cumulus-pallet-session-benchmarking", + "cumulus-pallet-xcm", + "cumulus-pallet-xcmp-queue", + "cumulus-primitives-core", + "cumulus-primitives-utility", + "frame-benchmarking", + "frame-executive", + "frame-support", + "frame-system", + "frame-system-benchmarking", + "frame-system-rpc-runtime-api", + "frame-try-runtime", + "hex-literal", + "log", + "pallet-asset-conversion", + "pallet-asset-conversion-tx-payment", + "pallet-assets", + "pallet-aura", + "pallet-authorship", + "pallet-balances", + "pallet-collator-selection", + "pallet-message-queue", + "pallet-multisig", + "pallet-nft-fractionalization", + "pallet-nfts", + "pallet-nfts-runtime-api", + "pallet-proxy", + "pallet-session", + "pallet-state-trie-migration", + "pallet-timestamp", + "pallet-transaction-payment", + "pallet-transaction-payment-rpc-runtime-api", + "pallet-uniques", + "pallet-utility", + "pallet-xcm", + "pallet-xcm-benchmarks", + "pallet-xcm-bridge-hub-router", + "parachains-common", + "parity-scale-codec", + "polkadot-core-primitives", + "polkadot-parachain-primitives", + "polkadot-runtime-common", + "primitive-types", + "rococo-runtime-constants", + "scale-info", + "smallvec", + "snowbridge-router-primitives", + "sp-api", + "sp-block-builder", + "sp-consensus-aura", + "sp-core", + "sp-genesis-builder", + "sp-inherents", + "sp-offchain", + "sp-runtime", + "sp-session", + "sp-std 8.0.0", + "sp-storage 13.0.0", + "sp-transaction-pool", + "sp-version", + "sp-weights", + "staging-parachain-info", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", + "substrate-wasm-builder", +] + [[package]] name = "asset-test-utils" version = "1.0.0" dependencies = [ "assets-common", - "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", "cumulus-pallet-xcmp-queue", "cumulus-primitives-core", @@ -741,7 +924,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "staging-parachain-info", "staging-xcm", "staging-xcm-builder", @@ -765,7 +948,7 @@ dependencies = [ "scale-info", "sp-api", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -888,8 +1071,8 @@ dependencies = [ [[package]] name = "bandersnatch_vrfs" -version = "0.0.1" -source = "git+https://github.com/w3f/ring-vrf?rev=4b09416#4b09416fd23383ec436ddac127d58c7b7cd392c6" +version = "0.0.3" +source = "git+https://github.com/w3f/ring-vrf?rev=cbc342e#cbc342e95d3cbcd3c5ba8d45af7200eb58e63502" dependencies = [ "ark-bls12-381", "ark-ec", @@ -904,6 +1087,8 @@ dependencies = [ "rand_core 0.6.4", "ring 0.1.0", "sha2 0.10.8", + "sp-ark-bls12-381", + "sp-ark-ed-on-bls12-381-bandersnatch", "zeroize", ] @@ -1036,6 +1221,7 @@ checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" dependencies = [ "funty", "radium", + "serde", "tap", "wyz", ] @@ -1183,7 +1369,7 @@ dependencies = [ ] [[package]] -name = "bp-asset-hub-wococo" +name = "bp-asset-hub-westend" version = "0.1.0" dependencies = [ "bp-xcm-bridge-hub-router", @@ -1203,7 +1389,7 @@ dependencies = [ "frame-system", "polkadot-primitives", "sp-api", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -1216,11 +1402,11 @@ dependencies = [ "frame-support", "sp-api", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] -name = "bp-bridge-hub-wococo" +name = "bp-bridge-hub-westend" version = "0.1.0" dependencies = [ "bp-bridge-hub-cumulus", @@ -1229,7 +1415,7 @@ dependencies = [ "frame-support", "sp-api", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -1245,7 +1431,7 @@ dependencies = [ "sp-consensus-grandpa", "sp-core", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -1259,7 +1445,7 @@ dependencies = [ "scale-info", "serde", "sp-core", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -1275,7 +1461,7 @@ dependencies = [ "scale-info", "sp-core", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -1292,7 +1478,7 @@ dependencies = [ "serde", "sp-core", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -1305,7 +1491,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -1317,7 +1503,7 @@ dependencies = [ "bp-runtime", "frame-support", "sp-api", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -1337,7 +1523,7 @@ dependencies = [ "sp-io", "sp-runtime", "sp-state-machine", - "sp-std", + "sp-std 8.0.0", "sp-trie", "trie-db", ] @@ -1357,21 +1543,20 @@ dependencies = [ "sp-consensus-grandpa", "sp-core", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "sp-trie", ] [[package]] -name = "bp-wococo" +name = "bp-westend" version = "0.1.0" dependencies = [ "bp-header-chain", "bp-polkadot-core", - "bp-rococo", "bp-runtime", "frame-support", "sp-api", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -1384,14 +1569,29 @@ dependencies = [ "sp-runtime", ] +[[package]] +name = "bridge-hub-common" +version = "0.1.0" +dependencies = [ + "cumulus-primitives-core", + "frame-support", + "pallet-message-queue", + "parity-scale-codec", + "scale-info", + "snowbridge-core", + "sp-runtime", + "sp-std 8.0.0", + "staging-xcm", +] + [[package]] name = "bridge-hub-rococo-runtime" version = "0.1.0" dependencies = [ "bp-asset-hub-rococo", - "bp-asset-hub-wococo", + "bp-asset-hub-westend", "bp-bridge-hub-rococo", - "bp-bridge-hub-wococo", + "bp-bridge-hub-westend", "bp-header-chain", "bp-messages", "bp-parachains", @@ -1399,7 +1599,8 @@ dependencies = [ "bp-relayers", "bp-rococo", "bp-runtime", - "bp-wococo", + "bp-westend", + "bridge-hub-common", "bridge-runtime-common", "cumulus-pallet-aura-ext", "cumulus-pallet-dmp-queue", @@ -1464,8 +1665,8 @@ dependencies = [ "sp-offchain", "sp-runtime", "sp-session", - "sp-std", - "sp-storage", + "sp-std 8.0.0", + "sp-storage 13.0.0", "sp-transaction-pool", "sp-version", "staging-parachain-info", @@ -1480,8 +1681,6 @@ name = "bridge-hub-test-utils" version = "0.1.0" dependencies = [ "asset-test-utils", - "bp-bridge-hub-rococo", - "bp-bridge-hub-wococo", "bp-header-chain", "bp-messages", "bp-parachains", @@ -1490,7 +1689,6 @@ dependencies = [ "bp-runtime", "bp-test-utils", "bridge-runtime-common", - "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", "cumulus-pallet-xcmp-queue", "frame-benchmarking", @@ -1515,7 +1713,7 @@ dependencies = [ "sp-io", "sp-keyring", "sp-runtime", - "sp-tracing", + "sp-tracing 10.0.0", "staging-parachain-info", "staging-xcm", "staging-xcm-builder", @@ -1549,7 +1747,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "sp-trie", "staging-xcm", "staging-xcm-builder", @@ -2297,7 +2495,7 @@ dependencies = [ "sp-application-crypto", "sp-consensus-aura", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -2305,6 +2503,7 @@ name = "cumulus-pallet-dmp-queue" version = "0.1.0" dependencies = [ "cumulus-primitives-core", + "frame-benchmarking", "frame-support", "frame-system", "log", @@ -2312,7 +2511,7 @@ dependencies = [ "scale-info", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "staging-xcm", ] @@ -2325,21 +2524,23 @@ dependencies = [ "cumulus-primitives-core", "cumulus-primitives-parachain-inherent", "environmental", + "frame-benchmarking", "frame-support", "frame-system", "impl-trait-for-tuples", "log", + "pallet-message-queue", "parity-scale-codec", "polkadot-parachain-primitives", "polkadot-runtime-parachains", "scale-info", "sp-core", - "sp-externalities", + "sp-externalities 0.19.0", "sp-inherents", "sp-io", "sp-runtime", "sp-state-machine", - "sp-std", + "sp-std 8.0.0", "sp-trie", "sp-version", "staging-xcm", @@ -2366,7 +2567,7 @@ dependencies = [ "pallet-session", "parity-scale-codec", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -2380,7 +2581,7 @@ dependencies = [ "scale-info", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "staging-xcm", ] @@ -2388,21 +2589,22 @@ dependencies = [ name = "cumulus-pallet-xcmp-queue" version = "0.1.0" dependencies = [ + "bounded-collections", "bp-xcm-bridge-hub-router", "cumulus-primitives-core", "frame-benchmarking", "frame-support", "frame-system", "log", + "pallet-message-queue", "parity-scale-codec", "polkadot-runtime-common", "polkadot-runtime-parachains", - "rand_chacha 0.3.1", "scale-info", "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "staging-xcm", "staging-xcm-executor", ] @@ -2418,7 +2620,7 @@ dependencies = [ "scale-info", "sp-api", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "sp-trie", "staging-xcm", ] @@ -2439,8 +2641,8 @@ dependencies = [ "sp-inherents", "sp-runtime", "sp-state-machine", - "sp-std", - "sp-storage", + "sp-std 8.0.0", + "sp-storage 13.0.0", "sp-trie", "tracing", ] @@ -2458,7 +2660,7 @@ dependencies = [ "polkadot-runtime-parachains", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -2490,7 +2692,7 @@ dependencies = [ "polkadot-primitives", "sp-runtime", "sp-state-machine", - "sp-std", + "sp-std 8.0.0", "sp-trie", ] @@ -2869,7 +3071,7 @@ dependencies = [ [[package]] name = "dleq_vrf" version = "0.0.2" -source = "git+https://github.com/w3f/ring-vrf?rev=4b09416#4b09416fd23383ec436ddac127d58c7b7cd392c6" +source = "git+https://github.com/w3f/ring-vrf?rev=cbc342e#cbc342e95d3cbcd3c5ba8d45af7200eb58e63502" dependencies = [ "ark-ec", "ark-ff 0.4.2", @@ -3078,6 +3280,26 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "enumflags2" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5998b4f30320c9d93aed72f63af821bfdac50465b75428fce77b48ec482c3939" +dependencies = [ + "enumflags2_derive", +] + +[[package]] +name = "enumflags2_derive" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f95e2801cd355d4a1a3e3953ce6ee5ae9603a5c833455343a8bfe3f44d418246" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + [[package]] name = "enumn" version = "0.1.12" @@ -3437,9 +3659,9 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-runtime-interface", - "sp-std", - "sp-storage", + "sp-runtime-interface 17.0.0", + "sp-std 8.0.0", + "sp-storage 13.0.0", "static_assertions", ] @@ -3466,7 +3688,7 @@ dependencies = [ "sp-core", "sp-npos-elections", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -3482,8 +3704,8 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", - "sp-tracing", + "sp-std 8.0.0", + "sp-tracing 10.0.0", ] [[package]] @@ -3503,6 +3725,7 @@ name = "frame-support" version = "4.0.0-dev" dependencies = [ "aquamarine", + "array-bytes 6.2.0", "bitflags 1.3.2", "docify", "environmental", @@ -3522,7 +3745,7 @@ dependencies = [ "sp-arithmetic", "sp-core", "sp-core-hashing-proc-macro", - "sp-debug-derive", + "sp-debug-derive 8.0.0", "sp-genesis-builder", "sp-inherents", "sp-io", @@ -3530,8 +3753,8 @@ dependencies = [ "sp-runtime", "sp-staking", "sp-state-machine", - "sp-std", - "sp-tracing", + "sp-std 8.0.0", + "sp-tracing 10.0.0", "sp-weights", "static_assertions", "tt-call", @@ -3580,6 +3803,7 @@ name = "frame-system" version = "4.0.0-dev" dependencies = [ "cfg-if", + "docify", "frame-support", "log", "parity-scale-codec", @@ -3588,7 +3812,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "sp-version", "sp-weights", ] @@ -3604,7 +3828,7 @@ dependencies = [ "scale-info", "sp-core", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -3623,7 +3847,7 @@ dependencies = [ "parity-scale-codec", "sp-api", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -4233,6 +4457,17 @@ dependencies = [ "parity-scale-codec", ] +[[package]] +name = "impl-num-traits" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "951641f13f873bff03d4bf19ae8bec531935ac0ac2cc775f84d7edfdcfed3f17" +dependencies = [ + "integer-sqrt", + "num-traits", + "uint", +] + [[package]] name = "impl-rlp" version = "0.3.0" @@ -5972,7 +6207,21 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", +] + +[[package]] +name = "pallet-asset-conversion-tx-payment" +version = "4.0.0-dev" +dependencies = [ + "frame-support", + "frame-system", + "pallet-asset-conversion", + "pallet-transaction-payment", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-std 8.0.0", ] [[package]] @@ -5986,7 +6235,7 @@ dependencies = [ "scale-info", "sp-core", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -6003,7 +6252,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -6018,7 +6267,7 @@ dependencies = [ "scale-info", "sp-core", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -6034,7 +6283,7 @@ dependencies = [ "sp-application-crypto", "sp-consensus-aura", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -6049,7 +6298,7 @@ dependencies = [ "sp-application-crypto", "sp-authority-discovery", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -6062,7 +6311,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -6085,7 +6334,7 @@ dependencies = [ "sp-runtime", "sp-session", "sp-staking", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -6099,7 +6348,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -6118,7 +6367,7 @@ dependencies = [ "scale-info", "sp-consensus-grandpa", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "sp-trie", ] @@ -6135,9 +6384,8 @@ dependencies = [ "num-traits", "parity-scale-codec", "scale-info", - "sp-core", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -6156,7 +6404,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "sp-trie", ] @@ -6176,7 +6424,7 @@ dependencies = [ "scale-info", "sp-arithmetic", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -6194,7 +6442,7 @@ dependencies = [ "scale-info", "sp-runtime", "sp-staking", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -6215,7 +6463,7 @@ dependencies = [ "sp-io", "sp-npos-elections", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "strum", ] @@ -6229,7 +6477,7 @@ dependencies = [ "parity-scale-codec", "sp-npos-elections", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -6247,13 +6495,29 @@ dependencies = [ "sp-io", "sp-runtime", "sp-staking", - "sp-std", + "sp-std 8.0.0", +] + +[[package]] +name = "pallet-identity" +version = "4.0.0-dev" +dependencies = [ + "enumflags2", + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-io", + "sp-runtime", + "sp-std 8.0.0", ] [[package]] name = "pallet-message-queue" version = "7.0.0-dev" dependencies = [ + "environmental", "frame-benchmarking", "frame-support", "frame-system", @@ -6264,7 +6528,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "sp-weights", ] @@ -6280,7 +6544,63 @@ dependencies = [ "scale-info", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", +] + +[[package]] +name = "pallet-nft-fractionalization" +version = "4.0.0-dev" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "pallet-assets", + "pallet-nfts", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-std 8.0.0", +] + +[[package]] +name = "pallet-nfts" +version = "4.0.0-dev" +dependencies = [ + "enumflags2", + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std 8.0.0", +] + +[[package]] +name = "pallet-nfts-runtime-api" +version = "4.0.0-dev" +dependencies = [ + "pallet-nfts", + "parity-scale-codec", + "sp-api", +] + +[[package]] +name = "pallet-proxy" +version = "4.0.0-dev" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-io", + "sp-runtime", + "sp-std 8.0.0", ] [[package]] @@ -6300,7 +6620,7 @@ dependencies = [ "sp-session", "sp-staking", "sp-state-machine", - "sp-std", + "sp-std 8.0.0", "sp-trie", ] @@ -6323,7 +6643,7 @@ dependencies = [ "sp-io", "sp-runtime", "sp-staking", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -6334,6 +6654,22 @@ dependencies = [ "sp-arithmetic", ] +[[package]] +name = "pallet-state-trie-migration" +version = "4.0.0-dev" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std 8.0.0", +] + [[package]] name = "pallet-timestamp" version = "4.0.0-dev" @@ -6348,8 +6684,8 @@ dependencies = [ "sp-inherents", "sp-io", "sp-runtime", - "sp-std", - "sp-storage", + "sp-std 8.0.0", + "sp-storage 13.0.0", "sp-timestamp", ] @@ -6365,7 +6701,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -6394,7 +6730,21 @@ dependencies = [ "serde", "sp-core", "sp-runtime", - "sp-std", + "sp-std 8.0.0", +] + +[[package]] +name = "pallet-uniques" +version = "4.0.0-dev" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-std 8.0.0", ] [[package]] @@ -6409,7 +6759,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -6423,7 +6773,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -6442,8 +6792,9 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "staging-xcm", + "staging-xcm-builder", "staging-xcm-executor", ] @@ -6459,7 +6810,7 @@ dependencies = [ "scale-info", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -6478,7 +6829,7 @@ dependencies = [ "scale-info", "sp-core", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "staging-xcm", "staging-xcm-builder", ] @@ -6498,6 +6849,7 @@ dependencies = [ "pallet-authorship", "pallet-balances", "pallet-collator-selection", + "pallet-message-queue", "parity-scale-codec", "polkadot-core-primitives", "polkadot-primitives", @@ -6508,7 +6860,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "staging-parachain-info", "staging-xcm", "staging-xcm-builder", @@ -6521,7 +6873,6 @@ name = "parachains-runtimes-test-utils" version = "1.0.0" dependencies = [ "assets-common", - "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", "cumulus-pallet-xcmp-queue", "cumulus-primitives-core", @@ -6541,8 +6892,8 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", - "sp-tracing", + "sp-std 8.0.0", + "sp-tracing 10.0.0", "staging-parachain-info", "staging-xcm", "staging-xcm-executor", @@ -6847,7 +7198,7 @@ dependencies = [ "scale-info", "sp-core", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -6912,6 +7263,7 @@ dependencies = [ name = "polkadot-node-primitives" version = "1.0.0" dependencies = [ + "bitvec", "bounded-vec", "futures", "parity-scale-codec", @@ -6934,6 +7286,7 @@ name = "polkadot-node-subsystem-types" version = "1.0.0" dependencies = [ "async-trait", + "bitvec", "derive_more", "futures", "orchestra", @@ -6986,7 +7339,7 @@ dependencies = [ "serde", "sp-core", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "sp-weights", ] @@ -7012,7 +7365,7 @@ dependencies = [ "sp-keystore", "sp-runtime", "sp-staking", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -7033,6 +7386,7 @@ dependencies = [ "pallet-balances", "pallet-election-provider-multi-phase", "pallet-fast-unstake", + "pallet-identity", "pallet-session", "pallet-staking", "pallet-staking-reward-fn", @@ -7057,7 +7411,7 @@ dependencies = [ "sp-runtime", "sp-session", "sp-staking", - "sp-std", + "sp-std 8.0.0", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -7072,8 +7426,8 @@ dependencies = [ "frame-benchmarking", "parity-scale-codec", "polkadot-primitives", - "sp-std", - "sp-tracing", + "sp-std 8.0.0", + "sp-tracing 10.0.0", ] [[package]] @@ -7116,7 +7470,7 @@ dependencies = [ "sp-runtime", "sp-session", "sp-staking", - "sp-std", + "sp-std 8.0.0", "staging-xcm", "staging-xcm-executor", "static_assertions", @@ -7252,6 +7606,7 @@ checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" dependencies = [ "fixed-hash", "impl-codec", + "impl-num-traits", "impl-rlp", "impl-serde", "scale-info", @@ -8155,7 +8510,7 @@ version = "4.1.0-dev" dependencies = [ "log", "sp-core", - "sp-wasm-interface", + "sp-wasm-interface 14.0.0", "thiserror", ] @@ -8191,7 +8546,6 @@ name = "sc-block-builder" version = "0.10.0-dev" dependencies = [ "parity-scale-codec", - "sc-client-api", "sp-api", "sp-block-builder", "sp-blockchain", @@ -8204,7 +8558,11 @@ dependencies = [ name = "sc-chain-spec" version = "4.0.0-dev" dependencies = [ + "array-bytes 6.2.0", + "docify", + "log", "memmap2", + "parity-scale-codec", "sc-chain-spec-derive", "sc-client-api", "sc-executor", @@ -8214,6 +8572,8 @@ dependencies = [ "serde_json", "sp-blockchain", "sp-core", + "sp-genesis-builder", + "sp-io", "sp-runtime", "sp-state-machine", ] @@ -8285,11 +8645,11 @@ dependencies = [ "sp-consensus", "sp-core", "sp-database", - "sp-externalities", + "sp-externalities 0.19.0", "sp-runtime", "sp-state-machine", "sp-statement-store", - "sp-storage", + "sp-storage 13.0.0", "sp-trie", "substrate-prometheus-endpoint", ] @@ -8354,13 +8714,13 @@ dependencies = [ "schnellru", "sp-api", "sp-core", - "sp-externalities", + "sp-externalities 0.19.0", "sp-io", "sp-panic-handler", - "sp-runtime-interface", + "sp-runtime-interface 17.0.0", "sp-trie", "sp-version", - "sp-wasm-interface", + "sp-wasm-interface 14.0.0", "tracing", ] @@ -8370,7 +8730,7 @@ version = "0.10.0-dev" dependencies = [ "sc-allocator", "sp-maybe-compressed-blob", - "sp-wasm-interface", + "sp-wasm-interface 14.0.0", "thiserror", "wasm-instrument", ] @@ -8387,8 +8747,8 @@ dependencies = [ "rustix 0.36.17", "sc-allocator", "sc-executor-common", - "sp-runtime-interface", - "sp-wasm-interface", + "sp-runtime-interface 17.0.0", + "sp-wasm-interface 14.0.0", "wasmtime", ] @@ -8574,6 +8934,7 @@ dependencies = [ "sp-runtime", "substrate-prometheus-endpoint", "thiserror", + "tokio", "tokio-stream", ] @@ -8679,6 +9040,7 @@ dependencies = [ "sp-api", "sp-blockchain", "sp-core", + "sp-rpc", "sp-runtime", "sp-version", "thiserror", @@ -8701,7 +9063,6 @@ dependencies = [ "parking_lot 0.12.1", "pin-project", "rand 0.8.5", - "sc-block-builder", "sc-chain-spec", "sc-client-api", "sc-client-db", @@ -8730,12 +9091,12 @@ dependencies = [ "sp-blockchain", "sp-consensus", "sp-core", - "sp-externalities", + "sp-externalities 0.19.0", "sp-keystore", "sp-runtime", "sp-session", "sp-state-machine", - "sp-storage", + "sp-storage 13.0.0", "sp-transaction-pool", "sp-transaction-storage-proof", "sp-trie", @@ -8763,6 +9124,7 @@ dependencies = [ name = "sc-sysinfo" version = "6.0.0-dev" dependencies = [ + "derive_more", "futures", "libc", "log", @@ -8774,7 +9136,7 @@ dependencies = [ "serde_json", "sp-core", "sp-io", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -8816,7 +9178,7 @@ dependencies = [ "sp-core", "sp-rpc", "sp-runtime", - "sp-tracing", + "sp-tracing 10.0.0", "thiserror", "tracing", "tracing-log", @@ -8852,7 +9214,7 @@ dependencies = [ "sp-blockchain", "sp-core", "sp-runtime", - "sp-tracing", + "sp-tracing 10.0.0", "sp-transaction-pool", "substrate-prometheus-endpoint", "thiserror", @@ -9288,7 +9650,7 @@ dependencies = [ "parity-scale-codec", "paste", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -9346,7 +9708,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "ssz_rs", "ssz_rs_derive", "static_assertions", @@ -9367,7 +9729,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -9381,7 +9743,7 @@ dependencies = [ "snowbridge-core", "sp-api", "sp-core", - "sp-std", + "sp-std 8.0.0", "staging-xcm", ] @@ -9392,6 +9754,7 @@ dependencies = [ "ethabi-decode", "frame-support", "frame-system", + "hex-literal", "parity-scale-codec", "polkadot-parachain-primitives", "scale-info", @@ -9399,9 +9762,11 @@ dependencies = [ "snowbridge-beacon-primitives", "sp-arithmetic", "sp-core", + "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "staging-xcm", + "staging-xcm-builder", ] [[package]] @@ -9422,7 +9787,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -9447,7 +9812,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "ssz_rs", "ssz_rs_derive", "static_assertions", @@ -9477,7 +9842,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "staging-xcm", "staging-xcm-builder", ] @@ -9486,6 +9851,7 @@ dependencies = [ name = "snowbridge-outbound-queue" version = "0.1.1" dependencies = [ + "bridge-hub-common", "ethabi-decode", "frame-benchmarking", "frame-support", @@ -9500,7 +9866,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "staging-xcm", ] @@ -9524,7 +9890,7 @@ dependencies = [ "snowbridge-outbound-queue-merkle-tree", "sp-api", "sp-core", - "sp-std", + "sp-std 8.0.0", "staging-xcm", ] @@ -9544,7 +9910,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -9568,6 +9934,7 @@ dependencies = [ name = "snowbridge-runtime-tests" version = "0.1.0" dependencies = [ + "asset-hub-rococo-runtime", "assets-common", "bridge-hub-rococo-runtime", "bridge-hub-test-utils", @@ -9632,8 +9999,8 @@ dependencies = [ "sp-offchain", "sp-runtime", "sp-session", - "sp-std", - "sp-storage", + "sp-std 8.0.0", + "sp-storage 13.0.0", "sp-transaction-pool", "sp-version", "staging-parachain-info", @@ -9690,11 +10057,11 @@ dependencies = [ "scale-info", "sp-api-proc-macro", "sp-core", - "sp-externalities", + "sp-externalities 0.19.0", "sp-metadata-ir", "sp-runtime", "sp-state-machine", - "sp-std", + "sp-std 8.0.0", "sp-trie", "sp-version", "thiserror", @@ -9722,7 +10089,7 @@ dependencies = [ "serde", "sp-core", "sp-io", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -9734,10 +10101,28 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-std", + "sp-std 8.0.0", "static_assertions", ] +[[package]] +name = "sp-ark-bls12-381" +version = "0.4.2" +source = "git+https://github.com/paritytech/arkworks-substrate#caa2eed74beb885dd07c7db5f916f2281dad818f" +dependencies = [ + "ark-bls12-381-ext", + "sp-crypto-ec-utils", +] + +[[package]] +name = "sp-ark-ed-on-bls12-381-bandersnatch" +version = "0.4.2" +source = "git+https://github.com/paritytech/arkworks-substrate#caa2eed74beb885dd07c7db5f916f2281dad818f" +dependencies = [ + "ark-ed-on-bls12-381-bandersnatch-ext", + "sp-crypto-ec-utils", +] + [[package]] name = "sp-authority-discovery" version = "4.0.0-dev" @@ -9747,7 +10132,7 @@ dependencies = [ "sp-api", "sp-application-crypto", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -9757,7 +10142,7 @@ dependencies = [ "sp-api", "sp-inherents", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -9803,7 +10188,7 @@ dependencies = [ "sp-consensus-slots", "sp-inherents", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "sp-timestamp", ] @@ -9821,7 +10206,7 @@ dependencies = [ "sp-core", "sp-inherents", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "sp-timestamp", ] @@ -9839,7 +10224,7 @@ dependencies = [ "sp-core", "sp-keystore", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -9849,7 +10234,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-std", + "sp-std 8.0.0", "sp-timestamp", ] @@ -9887,11 +10272,11 @@ dependencies = [ "secrecy", "serde", "sp-core-hashing", - "sp-debug-derive", - "sp-externalities", - "sp-runtime-interface", - "sp-std", - "sp-storage", + "sp-debug-derive 8.0.0", + "sp-externalities 0.19.0", + "sp-runtime-interface 17.0.0", + "sp-std 8.0.0", + "sp-storage 13.0.0", "ss58-registry", "substrate-bip39", "thiserror", @@ -9921,6 +10306,27 @@ dependencies = [ "syn 2.0.39", ] +[[package]] +name = "sp-crypto-ec-utils" +version = "0.4.1" +source = "git+https://github.com/paritytech/polkadot-sdk#b0b4451f31dcd9da04e2952d7c4cdcc219271b88" +dependencies = [ + "ark-bls12-377", + "ark-bls12-377-ext", + "ark-bls12-381", + "ark-bls12-381-ext", + "ark-bw6-761", + "ark-bw6-761-ext", + "ark-ec", + "ark-ed-on-bls12-377", + "ark-ed-on-bls12-377-ext", + "ark-ed-on-bls12-381-bandersnatch", + "ark-ed-on-bls12-381-bandersnatch-ext", + "ark-scale", + "sp-runtime-interface 17.0.0 (git+https://github.com/paritytech/polkadot-sdk)", + "sp-std 8.0.0 (git+https://github.com/paritytech/polkadot-sdk)", +] + [[package]] name = "sp-database" version = "4.0.0-dev" @@ -9938,14 +10344,35 @@ dependencies = [ "syn 2.0.39", ] +[[package]] +name = "sp-debug-derive" +version = "8.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk#b0b4451f31dcd9da04e2952d7c4cdcc219271b88" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + [[package]] name = "sp-externalities" version = "0.19.0" dependencies = [ "environmental", "parity-scale-codec", - "sp-std", - "sp-storage", + "sp-std 8.0.0", + "sp-storage 13.0.0", +] + +[[package]] +name = "sp-externalities" +version = "0.19.0" +source = "git+https://github.com/paritytech/polkadot-sdk#b0b4451f31dcd9da04e2952d7c4cdcc219271b88" +dependencies = [ + "environmental", + "parity-scale-codec", + "sp-std 8.0.0 (git+https://github.com/paritytech/polkadot-sdk)", + "sp-storage 13.0.0 (git+https://github.com/paritytech/polkadot-sdk)", ] [[package]] @@ -9955,7 +10382,7 @@ dependencies = [ "serde_json", "sp-api", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -9967,7 +10394,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "thiserror", ] @@ -9983,12 +10410,12 @@ dependencies = [ "rustversion", "secp256k1", "sp-core", - "sp-externalities", + "sp-externalities 0.19.0", "sp-keystore", - "sp-runtime-interface", + "sp-runtime-interface 17.0.0", "sp-state-machine", - "sp-std", - "sp-tracing", + "sp-std 8.0.0", + "sp-tracing 10.0.0", "sp-trie", "tracing", "tracing-core", @@ -10011,7 +10438,7 @@ dependencies = [ "parity-scale-codec", "parking_lot 0.12.1", "sp-core", - "sp-externalities", + "sp-externalities 0.19.0", "thiserror", ] @@ -10030,7 +10457,7 @@ dependencies = [ "frame-metadata", "parity-scale-codec", "scale-info", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10041,7 +10468,7 @@ dependencies = [ "scale-info", "sp-api", "sp-application-crypto", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10054,7 +10481,7 @@ dependencies = [ "sp-arithmetic", "sp-core", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10101,7 +10528,7 @@ dependencies = [ "sp-arithmetic", "sp-core", "sp-io", - "sp-std", + "sp-std 8.0.0", "sp-weights", ] @@ -10113,12 +10540,30 @@ dependencies = [ "impl-trait-for-tuples", "parity-scale-codec", "primitive-types", - "sp-externalities", - "sp-runtime-interface-proc-macro", - "sp-std", - "sp-storage", - "sp-tracing", - "sp-wasm-interface", + "sp-externalities 0.19.0", + "sp-runtime-interface-proc-macro 11.0.0", + "sp-std 8.0.0", + "sp-storage 13.0.0", + "sp-tracing 10.0.0", + "sp-wasm-interface 14.0.0", + "static_assertions", +] + +[[package]] +name = "sp-runtime-interface" +version = "17.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk#b0b4451f31dcd9da04e2952d7c4cdcc219271b88" +dependencies = [ + "bytes", + "impl-trait-for-tuples", + "parity-scale-codec", + "primitive-types", + "sp-externalities 0.19.0 (git+https://github.com/paritytech/polkadot-sdk)", + "sp-runtime-interface-proc-macro 11.0.0 (git+https://github.com/paritytech/polkadot-sdk)", + "sp-std 8.0.0 (git+https://github.com/paritytech/polkadot-sdk)", + "sp-storage 13.0.0 (git+https://github.com/paritytech/polkadot-sdk)", + "sp-tracing 10.0.0 (git+https://github.com/paritytech/polkadot-sdk)", + "sp-wasm-interface 14.0.0 (git+https://github.com/paritytech/polkadot-sdk)", "static_assertions", ] @@ -10133,6 +10578,18 @@ dependencies = [ "syn 2.0.39", ] +[[package]] +name = "sp-runtime-interface-proc-macro" +version = "11.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk#b0b4451f31dcd9da04e2952d7c4cdcc219271b88" +dependencies = [ + "Inflector", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.39", +] + [[package]] name = "sp-session" version = "4.0.0-dev" @@ -10144,7 +10601,7 @@ dependencies = [ "sp-keystore", "sp-runtime", "sp-staking", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10157,7 +10614,7 @@ dependencies = [ "serde", "sp-core", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10171,9 +10628,9 @@ dependencies = [ "rand 0.8.5", "smallvec", "sp-core", - "sp-externalities", + "sp-externalities 0.19.0", "sp-panic-handler", - "sp-std", + "sp-std 8.0.0", "sp-trie", "thiserror", "tracing", @@ -10195,10 +10652,10 @@ dependencies = [ "sp-api", "sp-application-crypto", "sp-core", - "sp-externalities", + "sp-externalities 0.19.0", "sp-runtime", - "sp-runtime-interface", - "sp-std", + "sp-runtime-interface 17.0.0", + "sp-std 8.0.0", "thiserror", "x25519-dalek 2.0.0", ] @@ -10207,6 +10664,11 @@ dependencies = [ name = "sp-std" version = "8.0.0" +[[package]] +name = "sp-std" +version = "8.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk#b0b4451f31dcd9da04e2952d7c4cdcc219271b88" + [[package]] name = "sp-storage" version = "13.0.0" @@ -10215,8 +10677,21 @@ dependencies = [ "parity-scale-codec", "ref-cast", "serde", - "sp-debug-derive", - "sp-std", + "sp-debug-derive 8.0.0", + "sp-std 8.0.0", +] + +[[package]] +name = "sp-storage" +version = "13.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk#b0b4451f31dcd9da04e2952d7c4cdcc219271b88" +dependencies = [ + "impl-serde", + "parity-scale-codec", + "ref-cast", + "serde", + "sp-debug-derive 8.0.0 (git+https://github.com/paritytech/polkadot-sdk)", + "sp-std 8.0.0 (git+https://github.com/paritytech/polkadot-sdk)", ] [[package]] @@ -10227,7 +10702,7 @@ dependencies = [ "parity-scale-codec", "sp-inherents", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "thiserror", ] @@ -10236,7 +10711,19 @@ name = "sp-tracing" version = "10.0.0" dependencies = [ "parity-scale-codec", - "sp-std", + "sp-std 8.0.0", + "tracing", + "tracing-core", + "tracing-subscriber", +] + +[[package]] +name = "sp-tracing" +version = "10.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk#b0b4451f31dcd9da04e2952d7c4cdcc219271b88" +dependencies = [ + "parity-scale-codec", + "sp-std 8.0.0 (git+https://github.com/paritytech/polkadot-sdk)", "tracing", "tracing-core", "tracing-subscriber", @@ -10260,7 +10747,7 @@ dependencies = [ "sp-core", "sp-inherents", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "sp-trie", ] @@ -10280,7 +10767,7 @@ dependencies = [ "scale-info", "schnellru", "sp-core", - "sp-std", + "sp-std 8.0.0", "thiserror", "tracing", "trie-db", @@ -10298,7 +10785,7 @@ dependencies = [ "serde", "sp-core-hashing-proc-macro", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "sp-version-proc-macro", "thiserror", ] @@ -10321,7 +10808,20 @@ dependencies = [ "impl-trait-for-tuples", "log", "parity-scale-codec", - "sp-std", + "sp-std 8.0.0", + "wasmtime", +] + +[[package]] +name = "sp-wasm-interface" +version = "14.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk#b0b4451f31dcd9da04e2952d7c4cdcc219271b88" +dependencies = [ + "anyhow", + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "sp-std 8.0.0 (git+https://github.com/paritytech/polkadot-sdk)", "wasmtime", ] @@ -10335,8 +10835,8 @@ dependencies = [ "smallvec", "sp-arithmetic", "sp-core", - "sp-debug-derive", - "sp-std", + "sp-debug-derive 8.0.0", + "sp-std 8.0.0", ] [[package]] @@ -10425,7 +10925,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-runtime", - "sp-std", + "sp-std 8.0.0", ] [[package]] @@ -10459,7 +10959,7 @@ dependencies = [ "sp-arithmetic", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "sp-weights", "staging-xcm", "staging-xcm-executor", @@ -10480,7 +10980,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", - "sp-std", + "sp-std 8.0.0", "sp-weights", "staging-xcm", ] diff --git a/polkadot-sdk b/polkadot-sdk index 2fc82bea16..e88d2b4412 160000 --- a/polkadot-sdk +++ b/polkadot-sdk @@ -1 +1 @@ -Subproject commit 2fc82bea16d8dadae925dd84a5b54b1507af90bc +Subproject commit e88d2b44124170c7dbcf9a003b9ffd0b6fedb001 From 40d07ce3b6e01efa1d91bf5c20a2af1496d6a5e5 Mon Sep 17 00:00:00 2001 From: ron Date: Wed, 29 Nov 2023 15:58:43 +0800 Subject: [PATCH 25/38] Simplify convert logic --- parachain/pallets/outbound-queue/src/lib.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/parachain/pallets/outbound-queue/src/lib.rs b/parachain/pallets/outbound-queue/src/lib.rs index 86ca2f7ac9..407f688be7 100644 --- a/parachain/pallets/outbound-queue/src/lib.rs +++ b/parachain/pallets/outbound-queue/src/lib.rs @@ -106,10 +106,7 @@ use snowbridge_core::{ use snowbridge_outbound_queue_merkle_tree::merkle_root; pub use snowbridge_outbound_queue_merkle_tree::MerkleProof; use sp_core::{H256, U256}; -use sp_runtime::{ - traits::{CheckedDiv, Hash}, - FixedPointNumber, -}; +use sp_runtime::traits::{CheckedDiv, Hash}; use sp_std::prelude::*; pub use types::{CommittedMessage, FeeConfigRecord, ProcessMessageOriginOf}; pub use weights::WeightInfo; @@ -372,12 +369,10 @@ pub mod pallet { let fee: u128 = fee.try_into().defensive_unwrap_or(u128::MAX); // convert to local currency - let fee = FixedU128::from(fee) + let fee = FixedU128::from_inner(fee) .checked_div(¶ms.exchange_rate) .expect("exchange rate is not zero; qed") - .into_inner() - .checked_div(FixedU128::accuracy()) - .expect("accuracy is not zero; qed"); + .into_inner(); // adjust fixed point to match local currency let fee = Self::convert_from_ether_decimals(fee); From a396ad37817b648aff42b66b076e8cdcdda92b9c Mon Sep 17 00:00:00 2001 From: ron Date: Wed, 29 Nov 2023 15:59:29 +0800 Subject: [PATCH 26/38] Format code --- smoketest/src/helper.rs | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/smoketest/src/helper.rs b/smoketest/src/helper.rs index 252609dac8..b08a62b605 100644 --- a/smoketest/src/helper.rs +++ b/smoketest/src/helper.rs @@ -12,6 +12,10 @@ use crate::{ utility, }, }, + penpal::{ + api::runtime_types as penpalTypes, + {self}, + }, relaychain, relaychain::api::runtime_types::{ pallet_xcm::pallet::Call as RelaychainPalletXcmCall, @@ -31,10 +35,6 @@ use crate::{ VersionedXcm as RelaychainVersionedXcm, }, }, - penpal::{ - api::runtime_types as penpalTypes, - {self}, - }, }, }; use ethers::{ @@ -46,6 +46,15 @@ use ethers::{ types::Log, }; use futures::StreamExt; +use penpalTypes::{ + pallet_xcm::pallet::Call, + penpal_runtime::RuntimeCall, + staging_xcm::v3::multilocation::MultiLocation, + xcm::{ + v3::{junction::Junction, junctions::Junctions}, + VersionedMultiLocation, VersionedXcm, + }, +}; use sp_core::{sr25519::Pair, Pair as PairT, H160}; use std::{ops::Deref, sync::Arc, time::Duration}; use subxt::{ @@ -54,15 +63,6 @@ use subxt::{ tx::{PairSigner, TxPayload}, Config, OnlineClient, PolkadotConfig, SubstrateConfig, }; -use penpalTypes::{ - staging_xcm::v3::multilocation::MultiLocation, - xcm::{ - v3::{junction::Junction, junctions::Junctions}, - VersionedMultiLocation, VersionedXcm, - }, - pallet_xcm::pallet::Call, - penpal_runtime::RuntimeCall -}; /// Custom config that works with Penpal pub enum PenpalConfig {} @@ -198,7 +198,10 @@ pub async fn send_sudo_xcm_transact( interior: Junctions::X1(Junction::Parachain(BRIDGE_HUB_PARA_ID)), })); - let sudo_call = penpal::api::sudo::calls::TransactionApi::sudo(&penpal::api::sudo::calls::TransactionApi,RuntimeCall::PolkadotXcm(Call::send { dest, message })); + let sudo_call = penpal::api::sudo::calls::TransactionApi::sudo( + &penpal::api::sudo::calls::TransactionApi, + RuntimeCall::PolkadotXcm(Call::send { dest, message }), + ); let owner: Pair = Pair::from_string("//Alice", None).expect("cannot create keypair"); From 9e321566c3eea501850c51b6c623edc9e2173cc8 Mon Sep 17 00:00:00 2001 From: ron Date: Wed, 29 Nov 2023 16:00:04 +0800 Subject: [PATCH 27/38] Add smoke test for set pricing params --- smoketest/tests/set_pricing_params.rs | 51 +++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 smoketest/tests/set_pricing_params.rs diff --git a/smoketest/tests/set_pricing_params.rs b/smoketest/tests/set_pricing_params.rs new file mode 100644 index 0000000000..2f3e857799 --- /dev/null +++ b/smoketest/tests/set_pricing_params.rs @@ -0,0 +1,51 @@ +use ethers::prelude::Address; +use snowbridge_smoketest::{ + constants::*, + contracts::{i_gateway, i_gateway::PricingParametersChangedFilter}, + helper::*, + parachains::bridgehub::api::{ + ethereum_control::events::PricingParametersChanged, + runtime_types::{ + self, + bridge_hub_rococo_runtime::RuntimeCall as BHRuntimeCall, + primitive_types::U256, + snowbridge_core::pricing::{PricingParameters, Rewards}, + sp_arithmetic::fixed_point::FixedU128, + }, + }, +}; + +#[tokio::test] +async fn set_pricing_params() { + let test_clients = initial_clients().await.expect("initialize clients"); + + let gateway_addr: Address = GATEWAY_PROXY_CONTRACT.into(); + let ethereum_client = *(test_clients.ethereum_client.clone()); + let gateway = i_gateway::IGateway::new(gateway_addr, ethereum_client.clone()); + let params = gateway.get_pricing_parameters().await.expect("get fees"); + println!("pricing params {:?}", params); + + let set_pricing_params_call = BHRuntimeCall::EthereumControl( + runtime_types::snowbridge_control::pallet::Call::set_pricing_parameters { + params: PricingParameters { + exchange_rate: FixedU128(5_000_000_000_000_000), + rewards: Rewards { + local: 2_000_000_000_000, + remote: U256([2_000_000_000_000_000, 0, 0, 0]), + }, + fee_per_gas: U256([30_000_000_000, 0, 0, 0]), + }, + }, + ); + + governance_bridgehub_call_from_relay_chain(vec![set_pricing_params_call]) + .await + .expect("set token fees"); + + wait_for_bridgehub_event::(&test_clients.bridge_hub_client).await; + + wait_for_ethereum_event::(&test_clients.ethereum_client).await; + + let params = gateway.get_pricing_parameters().await.expect("get fees"); + println!("pricing params {:?}", params); +} From 8d19ddbc2c83e153364db35c48ae321eba0f9bef Mon Sep 17 00:00:00 2001 From: ron Date: Wed, 29 Nov 2023 16:52:56 +0800 Subject: [PATCH 28/38] Load fee params from env --- smoketest/Cargo.lock | 1 + smoketest/Cargo.toml | 1 + smoketest/src/constants.rs | 17 +++++++++++++++++ smoketest/tests/set_token_transfer_fees.rs | 6 +++--- 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/smoketest/Cargo.lock b/smoketest/Cargo.lock index 9ff9b7441f..50add4eec1 100644 --- a/smoketest/Cargo.lock +++ b/smoketest/Cargo.lock @@ -3963,6 +3963,7 @@ dependencies = [ "futures", "hex", "hex-literal", + "lazy_static", "parity-scale-codec", "serde", "sp-core 16.0.0", diff --git a/smoketest/Cargo.toml b/smoketest/Cargo.toml index f82f1af784..d6779a83f5 100644 --- a/smoketest/Cargo.toml +++ b/smoketest/Cargo.toml @@ -15,6 +15,7 @@ serde = { version = "1.0", features = ["derive"] } subxt = { git = "https://github.com/paritytech/subxt.git", tag = "v0.27.1" } ethers = { git = "https://github.com/gakonst/ethers-rs", default-features = false, features = ["abigen", "ws"] } sp-core = "16.0.0" +lazy_static = "1.4.0" [dev-dependencies] xcm = { path = "../polkadot-sdk/polkadot/xcm", package="staging-xcm"} diff --git a/smoketest/src/constants.rs b/smoketest/src/constants.rs index 0c2ed43cb9..10e55b0e1b 100644 --- a/smoketest/src/constants.rs +++ b/smoketest/src/constants.rs @@ -1,4 +1,6 @@ use hex_literal::hex; +use lazy_static::lazy_static; +use std::{env, string::ToString}; // Todo: load all configs from env in consistent with set-env.sh pub const ASSET_HUB_PARA_ID: u32 = 1000; @@ -43,3 +45,18 @@ pub const PENPAL_SOVEREIGN: [u8; 32] = // SS58: DE14BzQ1bDXWPKeLoAqdLAm1GpyAWaWF1knF74cEZeomTBM pub const FERDIE: [u8; 32] = hex!("1cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c"); + +lazy_static! { + pub static ref REGISTER_TOKEN_FEE: u128 = env::var("REGISTER_TOKEN_FEE") + .unwrap_or("100000000000000000".to_string()) + .parse() + .unwrap(); + pub static ref CREATE_ASSET_FEE: u128 = env::var("CREATE_ASSET_FEE") + .unwrap_or("10000000000000".to_string()) + .parse() + .unwrap(); + pub static ref RESERVE_TRANSFER_FEE: u128 = env::var("RESERVE_TRANSFER_FEE") + .unwrap_or("20000000000".to_string()) + .parse() + .unwrap(); +} diff --git a/smoketest/tests/set_token_transfer_fees.rs b/smoketest/tests/set_token_transfer_fees.rs index c88ab28f1c..3465dff3e9 100644 --- a/smoketest/tests/set_token_transfer_fees.rs +++ b/smoketest/tests/set_token_transfer_fees.rs @@ -21,9 +21,9 @@ async fn set_token_transfer_fees() { let set_token_fees_call = BHRuntimeCall::EthereumControl( runtime_types::snowbridge_control::pallet::Call::set_token_transfer_fees { - create: 10_000_000_000_000, - transfer: 20_000_000_000, - register: 100_000_000_000_000_000, //0.1 Ether + create: *CREATE_ASSET_FEE, + transfer: *RESERVE_TRANSFER_FEE, + register: *REGISTER_TOKEN_FEE, }, ); From 8333be79144c2cacb826390ff62dbc8cc2fe0e46 Mon Sep 17 00:00:00 2001 From: ron Date: Wed, 29 Nov 2023 17:49:34 +0800 Subject: [PATCH 29/38] Add test for convert currency --- parachain/pallets/outbound-queue/src/test.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/parachain/pallets/outbound-queue/src/test.rs b/parachain/pallets/outbound-queue/src/test.rs index 98e22c1101..9bdc636495 100644 --- a/parachain/pallets/outbound-queue/src/test.rs +++ b/parachain/pallets/outbound-queue/src/test.rs @@ -13,7 +13,9 @@ use snowbridge_core::{ outbound::{Command, SendError, SendMessage}, ParaId, }; +use sp_arithmetic::FixedU128; use sp_core::H256; +use sp_runtime::FixedPointNumber; #[test] fn submit_messages_and_commit() { @@ -191,3 +193,17 @@ fn governance_message_does_not_get_the_chance_to_processed_in_same_block_when_co assert_eq!(footprint.storage.count, 0); }); } + +#[test] +fn convert_local_currency() { + new_tester().execute_with(|| { + let fee: u128 = 1_000_000; + let fee1 = FixedU128::from_inner(fee).into_inner(); + let fee2 = FixedU128::from(fee) + .into_inner() + .checked_div(FixedU128::accuracy()) + .expect("accuracy is not zero; qed"); + assert_eq!(fee, fee1); + assert_eq!(fee, fee2); + }); +} From e08c279857075bd5ce4c6745612aaf1af763b5fd Mon Sep 17 00:00:00 2001 From: ron Date: Wed, 29 Nov 2023 18:37:21 +0800 Subject: [PATCH 30/38] Load price configs from env --- contracts/src/DeployScript.sol | 2 +- smoketest/src/constants.rs | 12 ++++++++++++ smoketest/tests/set_pricing_params.rs | 9 +++------ web/packages/test/scripts/set-env.sh | 8 ++++++++ 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/contracts/src/DeployScript.sol b/contracts/src/DeployScript.sol index c3b16d3579..f7f9fde300 100644 --- a/contracts/src/DeployScript.sol +++ b/contracts/src/DeployScript.sol @@ -86,7 +86,7 @@ contract DeployScript is Script { registerTokenFee: uint128(vm.envUint("REGISTER_TOKEN_FEE")), assetHubCreateAssetFee: uint128(vm.envUint("CREATE_ASSET_FEE")), assetHubReserveTransferFee: uint128(vm.envUint("RESERVE_TRANSFER_FEE")), - exchangeRate: ud60x18(0.0025e18) + exchangeRate: ud60x18(vm.envUint("EXCHANGE_RATE")) }); GatewayProxy gateway = new GatewayProxy(address(gatewayLogic), abi.encode(config)); diff --git a/smoketest/src/constants.rs b/smoketest/src/constants.rs index 10e55b0e1b..d695f6891a 100644 --- a/smoketest/src/constants.rs +++ b/smoketest/src/constants.rs @@ -59,4 +59,16 @@ lazy_static! { .unwrap_or("20000000000".to_string()) .parse() .unwrap(); + pub static ref EXCHANGE_RATE: u128 = env::var("EXCHANGE_RATE") + .unwrap_or("2500000000000000".to_string()) + .parse() + .unwrap(); + pub static ref FEE_PER_GAS: u64 = + env::var("FEE_PER_GAS").unwrap_or("20000000000".to_string()).parse().unwrap(); + pub static ref LOCAL_REWARD: u128 = + env::var("LOCAL_REWARD").unwrap_or("1000000000000".to_string()).parse().unwrap(); + pub static ref REMOTE_REWARD: u64 = env::var("REMOTE_REWARD") + .unwrap_or("1000000000000000".to_string()) + .parse() + .unwrap(); } diff --git a/smoketest/tests/set_pricing_params.rs b/smoketest/tests/set_pricing_params.rs index 2f3e857799..fde7509a24 100644 --- a/smoketest/tests/set_pricing_params.rs +++ b/smoketest/tests/set_pricing_params.rs @@ -28,12 +28,9 @@ async fn set_pricing_params() { let set_pricing_params_call = BHRuntimeCall::EthereumControl( runtime_types::snowbridge_control::pallet::Call::set_pricing_parameters { params: PricingParameters { - exchange_rate: FixedU128(5_000_000_000_000_000), - rewards: Rewards { - local: 2_000_000_000_000, - remote: U256([2_000_000_000_000_000, 0, 0, 0]), - }, - fee_per_gas: U256([30_000_000_000, 0, 0, 0]), + exchange_rate: FixedU128(*EXCHANGE_RATE), + rewards: Rewards { local: *LOCAL_REWARD, remote: U256([*REMOTE_REWARD, 0, 0, 0]) }, + fee_per_gas: U256([*FEE_PER_GAS, 0, 0, 0]), }, }, ); diff --git a/web/packages/test/scripts/set-env.sh b/web/packages/test/scripts/set-env.sh index 315eea26fe..07b6c88fb2 100755 --- a/web/packages/test/scripts/set-env.sh +++ b/web/packages/test/scripts/set-env.sh @@ -91,6 +91,14 @@ export DELIVERY_COST="${DELIVERY_COST:-10000000000}" export CREATE_ASSET_FEE="${CREATE_ASSET_FEE:-10000000000}" export RESERVE_TRANSFER_FEE="${RESERVE_TRANSFER_FEE:-10000000000}" +## Price +export EXCHANGE_RATE="${EXCHANGE_RATE:-2500000000000000}" +export FEE_PER_GAS="${FEE_PER_GAS:-20000000000}" + +## Reward +export LOCAL_REWARD="${LOCAL_REWARD:-1000000000000}" +export REMOTE_REWARD="${REMOTE_REWARD:-1000000000000000}" + ## Vault export BRIDGE_HUB_INITIAL_DEPOSIT="${ETH_BRIDGE_HUB_INITIAL_DEPOSIT:-10000000000000000000}" From 7a68d89edfc756e2325900d35fac0f2600b0ca17 Mon Sep 17 00:00:00 2001 From: ron Date: Wed, 29 Nov 2023 18:49:31 +0800 Subject: [PATCH 31/38] Increase fee for test as enough --- smoketest/tests/send_token.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smoketest/tests/send_token.rs b/smoketest/tests/send_token.rs index d22d2c8726..f95b5c07cb 100644 --- a/smoketest/tests/send_token.rs +++ b/smoketest/tests/send_token.rs @@ -53,7 +53,7 @@ async fn send_token() { // Lock tokens into vault let amount: u128 = U256::from(value).low_u128(); - let fee: u128 = 1_000_000_000_000_000; + let fee: u128 = 30_000_000_000_000_000; let receipt = gateway .send_token( weth.address(), From edf418d7890a2d8d40e816cff1c0923e64840772 Mon Sep 17 00:00:00 2001 From: ron Date: Wed, 29 Nov 2023 21:20:36 +0800 Subject: [PATCH 32/38] Remove createAssetExecutionFee --- contracts/src/Assets.sol | 3 +- contracts/src/SubstrateTypes.sol | 8 +++- .../src/benchmarking/fixtures.rs | 2 +- parachain/pallets/inbound-queue/src/mock.rs | 10 +---- parachain/pallets/inbound-queue/src/test.rs | 4 +- .../primitives/router/src/inbound/mod.rs | 43 +++++++------------ polkadot-sdk | 2 +- 7 files changed, 29 insertions(+), 43 deletions(-) diff --git a/contracts/src/Assets.sol b/contracts/src/Assets.sol index c4b0785b33..8dfcbf858f 100644 --- a/contracts/src/Assets.sol +++ b/contracts/src/Assets.sol @@ -127,8 +127,9 @@ library Assets { revert InvalidToken(); } + AssetsStorage.Layout storage $ = AssetsStorage.layout(); ticket.costs = _registerTokenCosts(); - ticket.payload = SubstrateTypes.RegisterToken(token); + ticket.payload = SubstrateTypes.RegisterToken(token, $.assetHubCreateAssetFee); emit IGateway.TokenRegistrationSent(token); } diff --git a/contracts/src/SubstrateTypes.sol b/contracts/src/SubstrateTypes.sol index bbdd1f5870..6ecdd57beb 100644 --- a/contracts/src/SubstrateTypes.sol +++ b/contracts/src/SubstrateTypes.sol @@ -56,9 +56,13 @@ library SubstrateTypes { * `NativeTokensMessage::Create` */ // solhint-disable-next-line func-name-mixedcase - function RegisterToken(address token) internal view returns (bytes memory) { + function RegisterToken(address token, uint128 fee) internal view returns (bytes memory) { return bytes.concat( - bytes1(0x00), ScaleCodec.encodeU64(uint64(block.chainid)), bytes1(0x00), SubstrateTypes.H160(token) + bytes1(0x00), + ScaleCodec.encodeU64(uint64(block.chainid)), + bytes1(0x00), + SubstrateTypes.H160(token), + ScaleCodec.encodeU128(fee) ); } diff --git a/parachain/pallets/inbound-queue/src/benchmarking/fixtures.rs b/parachain/pallets/inbound-queue/src/benchmarking/fixtures.rs index 62092ceec3..67d9786e07 100644 --- a/parachain/pallets/inbound-queue/src/benchmarking/fixtures.rs +++ b/parachain/pallets/inbound-queue/src/benchmarking/fixtures.rs @@ -24,7 +24,7 @@ pub fn make_create_message() -> InboundQueueTest { hex!("c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539").into(), hex!("5f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0").into(), ], - data: hex!("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001e000f000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d0000").into(), + data: hex!("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002e000f000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d00e40b54020000000000000000000000000000000000000000000000000000000000").into(), }, proof: Proof { block_hash: hex!("7ce27351fff56e7f0f28774766ad46dcf9c05e5cc5cf2c1914de08b34da3d0c9").into(), diff --git a/parachain/pallets/inbound-queue/src/mock.rs b/parachain/pallets/inbound-queue/src/mock.rs index 123724b008..e43dc34e81 100644 --- a/parachain/pallets/inbound-queue/src/mock.rs +++ b/parachain/pallets/inbound-queue/src/mock.rs @@ -205,13 +205,7 @@ impl inbound_queue::Config for Test { type XcmSender = MockXcmSender; type WeightInfo = (); type GatewayAddress = GatewayAddress; - type MessageConverter = MessageToXcm< - CreateAssetCall, - CreateAssetExecutionFee, - CreateAssetDeposit, - AccountId, - Balance, - >; + type MessageConverter = MessageToXcm; type PricingParameters = Parameters; type ChannelLookup = MockChannelLookup; #[cfg(feature = "runtime-benchmarks")] @@ -270,7 +264,7 @@ pub fn mock_event_log() -> Log { hex!("5f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0").into(), ], // Nonce + Payload - data: hex!("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001e000f000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d0000").into(), + data: hex!("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002e000f000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d00e40b54020000000000000000000000000000000000000000000000000000000000").into(), } } diff --git a/parachain/pallets/inbound-queue/src/test.rs b/parachain/pallets/inbound-queue/src/test.rs index 875ae2e2a4..d952d3a925 100644 --- a/parachain/pallets/inbound-queue/src/test.rs +++ b/parachain/pallets/inbound-queue/src/test.rs @@ -34,8 +34,8 @@ fn test_submit_happy_path() { .into(), nonce: 1, message_id: [ - 168, 12, 232, 40, 69, 197, 207, 74, 203, 65, 199, 240, 164, 52, 244, 217, 62, 156, - 107, 237, 117, 203, 233, 78, 251, 233, 31, 54, 155, 124, 204, 201, + 156, 20, 62, 219, 36, 60, 225, 79, 64, 233, 45, 201, 222, 208, 39, 132, 37, 103, + 46, 160, 28, 26, 185, 50, 112, 230, 213, 92, 157, 236, 44, 190, ], } .into()]); diff --git a/parachain/primitives/router/src/inbound/mod.rs b/parachain/primitives/router/src/inbound/mod.rs index 873e1902d1..deb74d891c 100644 --- a/parachain/primitives/router/src/inbound/mod.rs +++ b/parachain/primitives/router/src/inbound/mod.rs @@ -46,6 +46,8 @@ pub enum Command { RegisterToken { /// The address of the ERC20 token to be bridged over to AssetHub token: H160, + /// XCM execution fee on AssetHub + fee: u128, }, /// Send a token to AssetHub or another parachain SendToken { @@ -85,25 +87,13 @@ pub enum Destination { }, } -pub struct MessageToXcm< - CreateAssetCall, - CreateAssetExecutionFee, - CreateAssetDeposit, - AccountId, - Balance, -> where +pub struct MessageToXcm +where CreateAssetCall: Get, - CreateAssetExecutionFee: Get, CreateAssetDeposit: Get, Balance: BalanceT, { - _phantom: PhantomData<( - CreateAssetCall, - CreateAssetExecutionFee, - CreateAssetDeposit, - AccountId, - Balance, - )>, + _phantom: PhantomData<(CreateAssetCall, CreateAssetDeposit, AccountId, Balance)>, } /// Reason why a message conversion failed. @@ -123,12 +113,10 @@ pub trait ConvertMessage { pub type CallIndex = [u8; 2]; -impl - ConvertMessage - for MessageToXcm +impl ConvertMessage + for MessageToXcm where CreateAssetCall: Get, - CreateAssetExecutionFee: Get, CreateAssetDeposit: Get, Balance: BalanceT + From, AccountId: Into<[u8; 32]>, @@ -140,29 +128,28 @@ where use Command::*; use VersionedMessage::*; match message { - V1(MessageV1 { chain_id, command: RegisterToken { token } }) => - Ok(Self::convert_register_token(chain_id, token)), + V1(MessageV1 { chain_id, command: RegisterToken { token, fee } }) => + Ok(Self::convert_register_token(chain_id, token, fee)), V1(MessageV1 { chain_id, command: SendToken { token, destination, amount, fee } }) => Ok(Self::convert_send_token(chain_id, token, destination, amount, fee)), } } } -impl - MessageToXcm +impl + MessageToXcm where CreateAssetCall: Get, - CreateAssetExecutionFee: Get, CreateAssetDeposit: Get, Balance: BalanceT + From, AccountId: Into<[u8; 32]>, { - fn convert_register_token(chain_id: u64, token: H160) -> (Xcm<()>, Balance) { + fn convert_register_token(chain_id: u64, token: H160, fee: u128) -> (Xcm<()>, Balance) { let network = Ethereum { chain_id }; - let fee: MultiAsset = (MultiLocation::parent(), CreateAssetExecutionFee::get()).into(); + let xcm_fee: MultiAsset = (MultiLocation::parent(), fee).into(); let deposit: MultiAsset = (MultiLocation::parent(), CreateAssetDeposit::get()).into(); - let total_amount = CreateAssetExecutionFee::get() + CreateAssetDeposit::get(); + let total_amount = fee + CreateAssetDeposit::get(); let total: MultiAsset = (MultiLocation::parent(), total_amount).into(); let bridge_location: MultiLocation = (Parent, Parent, GlobalConsensus(network)).into(); @@ -175,7 +162,7 @@ where // Teleport required fees. ReceiveTeleportedAsset(total.into()), // Pay for execution. - BuyExecution { fees: fee, weight_limit: Unlimited }, + BuyExecution { fees: xcm_fee, weight_limit: Unlimited }, // Fund the snowbridge sovereign with the required deposit for creation. DepositAsset { assets: Definite(deposit.into()), beneficiary: bridge_location }, // Change origin to the bridge. diff --git a/polkadot-sdk b/polkadot-sdk index e88d2b4412..e59a5b6260 160000 --- a/polkadot-sdk +++ b/polkadot-sdk @@ -1 +1 @@ -Subproject commit e88d2b44124170c7dbcf9a003b9ffd0b6fedb001 +Subproject commit e59a5b626045065f21176350efc2cc08f75379d6 From b719ad15f79e5cac693a360d9571594b7102dbd8 Mon Sep 17 00:00:00 2001 From: ron Date: Wed, 29 Nov 2023 21:52:35 +0800 Subject: [PATCH 33/38] Update sdk --- polkadot-sdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polkadot-sdk b/polkadot-sdk index e59a5b6260..21cf8340f5 160000 --- a/polkadot-sdk +++ b/polkadot-sdk @@ -1 +1 @@ -Subproject commit e59a5b626045065f21176350efc2cc08f75379d6 +Subproject commit 21cf8340f5a4c233ad6e58373ac245c4766b737e From ab55e8fabe37241243873b24489719b1e7ef00e7 Mon Sep 17 00:00:00 2001 From: Vincent Geddes Date: Wed, 29 Nov 2023 17:23:19 +0200 Subject: [PATCH 34/38] Rename fee getter functions to include a `quote` prefix --- contracts/src/Gateway.sol | 14 +-- contracts/src/interfaces/IGateway.sol | 18 ++-- contracts/test/Gateway.t.sol | 20 ++-- contracts/test/mocks/GatewayUpgradeMock.sol | 6 +- relayer/contracts/gateway.go | 114 ++++++++++---------- 5 files changed, 85 insertions(+), 87 deletions(-) diff --git a/contracts/src/Gateway.sol b/contracts/src/Gateway.sol index 32c5ac5ab8..4c9043d313 100644 --- a/contracts/src/Gateway.sol +++ b/contracts/src/Gateway.sol @@ -251,6 +251,11 @@ contract Gateway is IGateway, IInitializable { return _ensureAgent(agentID); } + function pricingParameters() external view returns (UD60x18, uint128) { + PricingStorage.Layout storage pricing = PricingStorage.layout(); + return (pricing.exchangeRate, pricing.deliveryCost); + } + function implementation() public view returns (address) { return ERC1967.load(); } @@ -464,17 +469,12 @@ contract Gateway is IGateway, IInitializable { emit PricingParametersChanged(); } - function getPricingParameters() external view returns (UD60x18, uint128) { - PricingStorage.Layout storage pricing = PricingStorage.layout(); - return (pricing.exchangeRate, pricing.deliveryCost); - } - /** * Assets */ // Total fee for registering a token - function registerTokenFee() external view returns (uint256) { + function quoteRegisterTokenFee() external view returns (uint256) { Costs memory costs = Assets.registerTokenCosts(); return _calculateFee(costs); } @@ -486,7 +486,7 @@ contract Gateway is IGateway, IInitializable { } // Total fee for sending a token - function sendTokenFee(address, ParaID destinationChain, uint128 destinationFee) external view returns (uint256) { + function quoteSendTokenFee(address, ParaID destinationChain, uint128 destinationFee) external view returns (uint256) { Costs memory costs = Assets.sendTokenCosts(ASSET_HUB_PARA_ID, destinationChain, destinationFee); return _calculateFee(costs); } diff --git a/contracts/src/interfaces/IGateway.sol b/contracts/src/interfaces/IGateway.sol index 56b89b4f25..5784e01b27 100644 --- a/contracts/src/interfaces/IGateway.sol +++ b/contracts/src/interfaces/IGateway.sol @@ -32,6 +32,9 @@ interface IGateway { // Emitted when the operating mode is changed event OperatingModeChanged(OperatingMode mode); + // Emitted when pricing params updated + event PricingParametersChanged(); + // Emitted when funds are withdrawn from an agent event AgentFundsWithdrawn(bytes32 indexed agentID, address indexed recipient, uint256 amount); @@ -43,6 +46,7 @@ interface IGateway { function channelOperatingModeOf(ChannelID channelID) external view returns (OperatingMode); function channelNoncesOf(ChannelID channelID) external view returns (uint64, uint64); function agentOf(bytes32 agentID) external view returns (address); + function pricingParameters() external view returns (UD60x18, uint128); function implementation() external view returns (address); /** @@ -75,22 +79,19 @@ interface IGateway { /// @dev Emitted when a command is sent to register a new wrapped token on AssetHub event TokenRegistrationSent(address token); - // @dev Emitted when pricing params updated - event PricingParametersChanged(); - - /// @dev Fee schedule in Ether for registering a token, covering + /// @dev Quote a fee in Ether for registering a token, covering /// 1. Delivery costs to BridgeHub /// 2. XCM Execution costs on AssetHub - function registerTokenFee() external view returns (uint256); + function quoteRegisterTokenFee() external view returns (uint256); /// @dev Send a message to the AssetHub parachain to register a new fungible asset /// in the `ForeignAssets` pallet. function registerToken(address token) external payable; - /// @dev Fees in Ether for sending a token + /// @dev Quote a fee in Ether for sending a token /// 1. Delivery costs to BridgeHub /// 2. XCM execution costs on destinationChain - function sendTokenFee(address token, ParaID destinationChain, uint128 destinationFee) + function quoteSendTokenFee(address token, ParaID destinationChain, uint128 destinationFee) external view returns (uint256); @@ -103,7 +104,4 @@ interface IGateway { uint128 destinationFee, uint128 amount ) external payable; - - /// @dev Get pricing params (exchangeRate,deliveryCost) - function getPricingParameters() external view returns (UD60x18, uint128); } diff --git a/contracts/test/Gateway.t.sol b/contracts/test/Gateway.t.sol index bd0588292d..250e9b945a 100644 --- a/contracts/test/Gateway.t.sol +++ b/contracts/test/Gateway.t.sol @@ -292,7 +292,7 @@ contract GatewayTest is Test { address user = makeAddr("user"); deal(address(token), user, 1); - uint256 fee = IGateway(address(gateway)).sendTokenFee(address(token), ParaID.wrap(0), 1); + uint256 fee = IGateway(address(gateway)).quoteSendTokenFee(address(token), ParaID.wrap(0), 1); // Let gateway lock up to 1 tokens hoax(user); @@ -573,7 +573,7 @@ contract GatewayTest is Test { vm.expectEmit(true, false, false, false); emit IGateway.OutboundMessageAccepted(assetHubParaID.into(), 1, messageID, bytes("")); - uint256 totalFee = GatewayMock(address(gateway)).registerTokenFee(); + uint256 totalFee = GatewayMock(address(gateway)).quoteRegisterTokenFee(); uint256 balanceBefore = address(this).balance; IGateway(address(gateway)).registerToken{value: totalFee + 1 ether}(address(token)); @@ -592,7 +592,7 @@ contract GatewayTest is Test { // Multilocation for recipient ParaID destPara = ParaID.wrap(2043); - uint256 fee = IGateway(address(gateway)).sendTokenFee(address(token), destPara, 1); + uint256 fee = IGateway(address(gateway)).quoteSendTokenFee(address(token), destPara, 1); vm.expectEmit(true, true, false, true); emit IGateway.TokenSent(address(this), address(token), destPara, recipientAddress32, 1); @@ -611,7 +611,7 @@ contract GatewayTest is Test { // Multilocation for recipient ParaID destPara = assetHubParaID; - uint256 fee = IGateway(address(gateway)).sendTokenFee(address(token), destPara, 1); + uint256 fee = IGateway(address(gateway)).quoteSendTokenFee(address(token), destPara, 1); vm.expectEmit(true, true, false, true); emit IGateway.TokenSent(address(this), address(token), destPara, recipientAddress32, 1); @@ -630,7 +630,7 @@ contract GatewayTest is Test { // Multilocation for recipient ParaID destPara = ParaID.wrap(2043); - uint256 fee = IGateway(address(gateway)).sendTokenFee(address(token), destPara, 1); + uint256 fee = IGateway(address(gateway)).quoteSendTokenFee(address(token), destPara, 1); vm.expectEmit(true, true, false, true); emit IGateway.TokenSent(address(this), address(token), destPara, recipientAddress20, 1); @@ -743,7 +743,7 @@ contract GatewayTest is Test { OperatingMode channelMode = gw.channelOperatingModeOf(assetHubParaID.into()); assertEq(uint256(channelMode), 0); - (, uint128 fee) = gw.getPricingParameters(); + (, uint128 fee) = gw.pricingParameters(); assertEq(fee, 10000000000); (uint64 inbound, uint64 outbound) = gw.channelNoncesOf(assetHubParaID.into()); @@ -776,7 +776,7 @@ contract GatewayTest is Test { } function testSetTokenFees() public { - uint256 fee = IGateway(address(gateway)).registerTokenFee(); + uint256 fee = IGateway(address(gateway)).quoteRegisterTokenFee(); assertEq(fee, 5000000000000000); // Double the assetHubCreateAssetFee GatewayMock(address(gateway)).setTokenTransferFeesPublic( @@ -788,7 +788,7 @@ contract GatewayTest is Test { }) ) ); - fee = IGateway(address(gateway)).registerTokenFee(); + fee = IGateway(address(gateway)).quoteRegisterTokenFee(); // since deliveryCost not changed, so the total fee increased only by 50% assertEq(fee, 7500000000000000); } @@ -802,7 +802,7 @@ contract GatewayTest is Test { } function testSetPricingParameters() public { - uint256 fee = IGateway(address(gateway)).registerTokenFee(); + uint256 fee = IGateway(address(gateway)).quoteRegisterTokenFee(); assertEq(fee, 5000000000000000); // Double the exchangeRate GatewayMock(address(gateway)).setPricingParametersPublic( @@ -813,7 +813,7 @@ contract GatewayTest is Test { }) ) ); - fee = IGateway(address(gateway)).registerTokenFee(); + fee = IGateway(address(gateway)).quoteRegisterTokenFee(); assertEq(fee, 10000000000000000); } } diff --git a/contracts/test/mocks/GatewayUpgradeMock.sol b/contracts/test/mocks/GatewayUpgradeMock.sol index fc46119a3a..de2b769356 100644 --- a/contracts/test/mocks/GatewayUpgradeMock.sol +++ b/contracts/test/mocks/GatewayUpgradeMock.sol @@ -35,13 +35,13 @@ contract GatewayUpgradeMock is IGateway, IInitializable { function submitInbound(InboundMessage calldata, bytes32[] calldata, Verification.Proof calldata) external {} - function registerTokenFee() external pure returns (uint256) { + function quoteRegisterTokenFee() external pure returns (uint256) { return 1; } function registerToken(address) external payable {} - function sendTokenFee(address, ParaID, uint128) external pure returns (uint256) { + function quoteSendTokenFee(address, ParaID, uint128) external pure returns (uint256) { return 1; } @@ -55,7 +55,7 @@ contract GatewayUpgradeMock is IGateway, IInitializable { emit Initialized(d0, d1); } - function getPricingParameters() external pure returns (UD60x18, uint128) { + function pricingParameters() external pure returns (UD60x18, uint128) { return (convert(0), uint128(0)); } } diff --git a/relayer/contracts/gateway.go b/relayer/contracts/gateway.go index ae1a9e87ad..b7523bf991 100644 --- a/relayer/contracts/gateway.go +++ b/relayer/contracts/gateway.go @@ -91,7 +91,7 @@ type VerificationProof struct { // GatewayMetaData contains all meta data concerning the Gateway contract. var GatewayMetaData = &bind.MetaData{ - ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"agentID\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"agent\",\"type\":\"address\"}],\"name\":\"AgentCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"agentID\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"AgentFundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"ChannelID\",\"name\":\"channelID\",\"type\":\"bytes32\"}],\"name\":\"ChannelCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"ChannelID\",\"name\":\"channelID\",\"type\":\"bytes32\"}],\"name\":\"ChannelUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"ChannelID\",\"name\":\"channelID\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"messageID\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"name\":\"InboundMessageDispatched\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"enumOperatingMode\",\"name\":\"mode\",\"type\":\"uint8\"}],\"name\":\"OperatingModeChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"ChannelID\",\"name\":\"channelID\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"messageID\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"}],\"name\":\"OutboundMessageAccepted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"PricingParametersChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"TokenRegistrationSent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"ParaID\",\"name\":\"destinationChain\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"enumKind\",\"name\":\"kind\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"indexed\":false,\"internalType\":\"structMultiAddress\",\"name\":\"destinationAddress\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"}],\"name\":\"TokenSent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"TokenTransferFeesChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"Upgraded\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"agentID\",\"type\":\"bytes32\"}],\"name\":\"agentOf\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"ChannelID\",\"name\":\"channelID\",\"type\":\"bytes32\"}],\"name\":\"channelNoncesOf\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"ChannelID\",\"name\":\"channelID\",\"type\":\"bytes32\"}],\"name\":\"channelOperatingModeOf\",\"outputs\":[{\"internalType\":\"enumOperatingMode\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPricingParameters\",\"outputs\":[{\"internalType\":\"UD60x18\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"implementation\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"operatingMode\",\"outputs\":[{\"internalType\":\"enumOperatingMode\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"registerToken\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"registerTokenFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"ParaID\",\"name\":\"destinationChain\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"enumKind\",\"name\":\"kind\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"internalType\":\"structMultiAddress\",\"name\":\"destinationAddress\",\"type\":\"tuple\"},{\"internalType\":\"uint128\",\"name\":\"destinationFee\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"}],\"name\":\"sendToken\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"ParaID\",\"name\":\"destinationChain\",\"type\":\"uint32\"},{\"internalType\":\"uint128\",\"name\":\"destinationFee\",\"type\":\"uint128\"}],\"name\":\"sendTokenFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"ChannelID\",\"name\":\"channelID\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"internalType\":\"enumCommand\",\"name\":\"command\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"params\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"maxDispatchGas\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"maxRefund\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"reward\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"internalType\":\"structInboundMessage\",\"name\":\"message\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"leafProof\",\"type\":\"bytes32[]\"},{\"components\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"parentHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"number\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"extrinsicsRoot\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"kind\",\"type\":\"uint256\"},{\"internalType\":\"bytes4\",\"name\":\"consensusEngineID\",\"type\":\"bytes4\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"internalType\":\"structVerification.DigestItem[]\",\"name\":\"digestItems\",\"type\":\"tuple[]\"}],\"internalType\":\"structVerification.ParachainHeader\",\"name\":\"header\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"pos\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"width\",\"type\":\"uint256\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"internalType\":\"structVerification.HeadProof\",\"name\":\"headProof\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"parentNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"parentHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"nextAuthoritySetID\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"nextAuthoritySetLen\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"nextAuthoritySetRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structVerification.MMRLeafPartial\",\"name\":\"leafPartial\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"leafProof\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"leafProofOrder\",\"type\":\"uint256\"}],\"internalType\":\"structVerification.Proof\",\"name\":\"headerProof\",\"type\":\"tuple\"}],\"name\":\"submitInbound\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"agentID\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"agent\",\"type\":\"address\"}],\"name\":\"AgentCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"agentID\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"AgentFundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"ChannelID\",\"name\":\"channelID\",\"type\":\"bytes32\"}],\"name\":\"ChannelCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"ChannelID\",\"name\":\"channelID\",\"type\":\"bytes32\"}],\"name\":\"ChannelUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"ChannelID\",\"name\":\"channelID\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"messageID\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"name\":\"InboundMessageDispatched\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"enumOperatingMode\",\"name\":\"mode\",\"type\":\"uint8\"}],\"name\":\"OperatingModeChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"ChannelID\",\"name\":\"channelID\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"messageID\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"}],\"name\":\"OutboundMessageAccepted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"PricingParametersChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"TokenRegistrationSent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"ParaID\",\"name\":\"destinationChain\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"enumKind\",\"name\":\"kind\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"indexed\":false,\"internalType\":\"structMultiAddress\",\"name\":\"destinationAddress\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"}],\"name\":\"TokenSent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"TokenTransferFeesChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"Upgraded\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"agentID\",\"type\":\"bytes32\"}],\"name\":\"agentOf\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"ChannelID\",\"name\":\"channelID\",\"type\":\"bytes32\"}],\"name\":\"channelNoncesOf\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"ChannelID\",\"name\":\"channelID\",\"type\":\"bytes32\"}],\"name\":\"channelOperatingModeOf\",\"outputs\":[{\"internalType\":\"enumOperatingMode\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"implementation\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"operatingMode\",\"outputs\":[{\"internalType\":\"enumOperatingMode\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pricingParameters\",\"outputs\":[{\"internalType\":\"UD60x18\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"quoteRegisterTokenFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"ParaID\",\"name\":\"destinationChain\",\"type\":\"uint32\"},{\"internalType\":\"uint128\",\"name\":\"destinationFee\",\"type\":\"uint128\"}],\"name\":\"quoteSendTokenFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"registerToken\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"ParaID\",\"name\":\"destinationChain\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"enumKind\",\"name\":\"kind\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"internalType\":\"structMultiAddress\",\"name\":\"destinationAddress\",\"type\":\"tuple\"},{\"internalType\":\"uint128\",\"name\":\"destinationFee\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"}],\"name\":\"sendToken\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"ChannelID\",\"name\":\"channelID\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"internalType\":\"enumCommand\",\"name\":\"command\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"params\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"maxDispatchGas\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"maxRefund\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"reward\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"internalType\":\"structInboundMessage\",\"name\":\"message\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"leafProof\",\"type\":\"bytes32[]\"},{\"components\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"parentHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"number\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"extrinsicsRoot\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"kind\",\"type\":\"uint256\"},{\"internalType\":\"bytes4\",\"name\":\"consensusEngineID\",\"type\":\"bytes4\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"internalType\":\"structVerification.DigestItem[]\",\"name\":\"digestItems\",\"type\":\"tuple[]\"}],\"internalType\":\"structVerification.ParachainHeader\",\"name\":\"header\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"pos\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"width\",\"type\":\"uint256\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"internalType\":\"structVerification.HeadProof\",\"name\":\"headProof\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"parentNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"parentHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"nextAuthoritySetID\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"nextAuthoritySetLen\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"nextAuthoritySetRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structVerification.MMRLeafPartial\",\"name\":\"leafPartial\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"leafProof\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"leafProofOrder\",\"type\":\"uint256\"}],\"internalType\":\"structVerification.Proof\",\"name\":\"headerProof\",\"type\":\"tuple\"}],\"name\":\"submitInbound\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", } // GatewayABI is the input ABI used to generate the binding from. @@ -334,38 +334,6 @@ func (_Gateway *GatewayCallerSession) ChannelOperatingModeOf(channelID [32]byte) return _Gateway.Contract.ChannelOperatingModeOf(&_Gateway.CallOpts, channelID) } -// GetPricingParameters is a free data retrieval call binding the contract method 0xe92faaed. -// -// Solidity: function getPricingParameters() view returns(uint256, uint128) -func (_Gateway *GatewayCaller) GetPricingParameters(opts *bind.CallOpts) (*big.Int, *big.Int, error) { - var out []interface{} - err := _Gateway.contract.Call(opts, &out, "getPricingParameters") - - if err != nil { - return *new(*big.Int), *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - out1 := *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) - - return out0, out1, err - -} - -// GetPricingParameters is a free data retrieval call binding the contract method 0xe92faaed. -// -// Solidity: function getPricingParameters() view returns(uint256, uint128) -func (_Gateway *GatewaySession) GetPricingParameters() (*big.Int, *big.Int, error) { - return _Gateway.Contract.GetPricingParameters(&_Gateway.CallOpts) -} - -// GetPricingParameters is a free data retrieval call binding the contract method 0xe92faaed. -// -// Solidity: function getPricingParameters() view returns(uint256, uint128) -func (_Gateway *GatewayCallerSession) GetPricingParameters() (*big.Int, *big.Int, error) { - return _Gateway.Contract.GetPricingParameters(&_Gateway.CallOpts) -} - // Implementation is a free data retrieval call binding the contract method 0x5c60da1b. // // Solidity: function implementation() view returns(address) @@ -428,12 +396,44 @@ func (_Gateway *GatewayCallerSession) OperatingMode() (uint8, error) { return _Gateway.Contract.OperatingMode(&_Gateway.CallOpts) } -// RegisterTokenFee is a free data retrieval call binding the contract method 0x85f63dcb. +// PricingParameters is a free data retrieval call binding the contract method 0x0b617646. +// +// Solidity: function pricingParameters() view returns(uint256, uint128) +func (_Gateway *GatewayCaller) PricingParameters(opts *bind.CallOpts) (*big.Int, *big.Int, error) { + var out []interface{} + err := _Gateway.contract.Call(opts, &out, "pricingParameters") + + if err != nil { + return *new(*big.Int), *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + out1 := *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + + return out0, out1, err + +} + +// PricingParameters is a free data retrieval call binding the contract method 0x0b617646. +// +// Solidity: function pricingParameters() view returns(uint256, uint128) +func (_Gateway *GatewaySession) PricingParameters() (*big.Int, *big.Int, error) { + return _Gateway.Contract.PricingParameters(&_Gateway.CallOpts) +} + +// PricingParameters is a free data retrieval call binding the contract method 0x0b617646. +// +// Solidity: function pricingParameters() view returns(uint256, uint128) +func (_Gateway *GatewayCallerSession) PricingParameters() (*big.Int, *big.Int, error) { + return _Gateway.Contract.PricingParameters(&_Gateway.CallOpts) +} + +// QuoteRegisterTokenFee is a free data retrieval call binding the contract method 0x805ce31d. // -// Solidity: function registerTokenFee() view returns(uint256) -func (_Gateway *GatewayCaller) RegisterTokenFee(opts *bind.CallOpts) (*big.Int, error) { +// Solidity: function quoteRegisterTokenFee() view returns(uint256) +func (_Gateway *GatewayCaller) QuoteRegisterTokenFee(opts *bind.CallOpts) (*big.Int, error) { var out []interface{} - err := _Gateway.contract.Call(opts, &out, "registerTokenFee") + err := _Gateway.contract.Call(opts, &out, "quoteRegisterTokenFee") if err != nil { return *new(*big.Int), err @@ -445,26 +445,26 @@ func (_Gateway *GatewayCaller) RegisterTokenFee(opts *bind.CallOpts) (*big.Int, } -// RegisterTokenFee is a free data retrieval call binding the contract method 0x85f63dcb. +// QuoteRegisterTokenFee is a free data retrieval call binding the contract method 0x805ce31d. // -// Solidity: function registerTokenFee() view returns(uint256) -func (_Gateway *GatewaySession) RegisterTokenFee() (*big.Int, error) { - return _Gateway.Contract.RegisterTokenFee(&_Gateway.CallOpts) +// Solidity: function quoteRegisterTokenFee() view returns(uint256) +func (_Gateway *GatewaySession) QuoteRegisterTokenFee() (*big.Int, error) { + return _Gateway.Contract.QuoteRegisterTokenFee(&_Gateway.CallOpts) } -// RegisterTokenFee is a free data retrieval call binding the contract method 0x85f63dcb. +// QuoteRegisterTokenFee is a free data retrieval call binding the contract method 0x805ce31d. // -// Solidity: function registerTokenFee() view returns(uint256) -func (_Gateway *GatewayCallerSession) RegisterTokenFee() (*big.Int, error) { - return _Gateway.Contract.RegisterTokenFee(&_Gateway.CallOpts) +// Solidity: function quoteRegisterTokenFee() view returns(uint256) +func (_Gateway *GatewayCallerSession) QuoteRegisterTokenFee() (*big.Int, error) { + return _Gateway.Contract.QuoteRegisterTokenFee(&_Gateway.CallOpts) } -// SendTokenFee is a free data retrieval call binding the contract method 0x783b4fab. +// QuoteSendTokenFee is a free data retrieval call binding the contract method 0x928bc49d. // -// Solidity: function sendTokenFee(address token, uint32 destinationChain, uint128 destinationFee) view returns(uint256) -func (_Gateway *GatewayCaller) SendTokenFee(opts *bind.CallOpts, token common.Address, destinationChain uint32, destinationFee *big.Int) (*big.Int, error) { +// Solidity: function quoteSendTokenFee(address token, uint32 destinationChain, uint128 destinationFee) view returns(uint256) +func (_Gateway *GatewayCaller) QuoteSendTokenFee(opts *bind.CallOpts, token common.Address, destinationChain uint32, destinationFee *big.Int) (*big.Int, error) { var out []interface{} - err := _Gateway.contract.Call(opts, &out, "sendTokenFee", token, destinationChain, destinationFee) + err := _Gateway.contract.Call(opts, &out, "quoteSendTokenFee", token, destinationChain, destinationFee) if err != nil { return *new(*big.Int), err @@ -476,18 +476,18 @@ func (_Gateway *GatewayCaller) SendTokenFee(opts *bind.CallOpts, token common.Ad } -// SendTokenFee is a free data retrieval call binding the contract method 0x783b4fab. +// QuoteSendTokenFee is a free data retrieval call binding the contract method 0x928bc49d. // -// Solidity: function sendTokenFee(address token, uint32 destinationChain, uint128 destinationFee) view returns(uint256) -func (_Gateway *GatewaySession) SendTokenFee(token common.Address, destinationChain uint32, destinationFee *big.Int) (*big.Int, error) { - return _Gateway.Contract.SendTokenFee(&_Gateway.CallOpts, token, destinationChain, destinationFee) +// Solidity: function quoteSendTokenFee(address token, uint32 destinationChain, uint128 destinationFee) view returns(uint256) +func (_Gateway *GatewaySession) QuoteSendTokenFee(token common.Address, destinationChain uint32, destinationFee *big.Int) (*big.Int, error) { + return _Gateway.Contract.QuoteSendTokenFee(&_Gateway.CallOpts, token, destinationChain, destinationFee) } -// SendTokenFee is a free data retrieval call binding the contract method 0x783b4fab. +// QuoteSendTokenFee is a free data retrieval call binding the contract method 0x928bc49d. // -// Solidity: function sendTokenFee(address token, uint32 destinationChain, uint128 destinationFee) view returns(uint256) -func (_Gateway *GatewayCallerSession) SendTokenFee(token common.Address, destinationChain uint32, destinationFee *big.Int) (*big.Int, error) { - return _Gateway.Contract.SendTokenFee(&_Gateway.CallOpts, token, destinationChain, destinationFee) +// Solidity: function quoteSendTokenFee(address token, uint32 destinationChain, uint128 destinationFee) view returns(uint256) +func (_Gateway *GatewayCallerSession) QuoteSendTokenFee(token common.Address, destinationChain uint32, destinationFee *big.Int) (*big.Int, error) { + return _Gateway.Contract.QuoteSendTokenFee(&_Gateway.CallOpts, token, destinationChain, destinationFee) } // RegisterToken is a paid mutator transaction binding the contract method 0x09824a80. From d26b6bd23b321c4da6d9e9bf2a8c682b708b1c88 Mon Sep 17 00:00:00 2001 From: Vincent Geddes Date: Wed, 29 Nov 2023 21:12:05 +0200 Subject: [PATCH 35/38] improve setTokenTransferFees API, and add benchmarks --- contracts/src/Gateway.sol | 10 +- parachain/pallets/control/src/benchmarking.rs | 36 +++-- parachain/pallets/control/src/lib.rs | 45 ++++-- parachain/pallets/control/src/tests.rs | 141 ++++++++++++------ parachain/pallets/control/src/weights.rs | 21 +++ parachain/primitives/core/src/outbound.rs | 25 ++-- 6 files changed, 194 insertions(+), 84 deletions(-) diff --git a/contracts/src/Gateway.sol b/contracts/src/Gateway.sol index 4c9043d313..484922e59e 100644 --- a/contracts/src/Gateway.sol +++ b/contracts/src/Gateway.sol @@ -439,8 +439,8 @@ contract Gateway is IGateway, IInitializable { uint128 assetHubCreateAssetFee; /// @dev The remote fee (DOT) for send tokens to AssetHub uint128 assetHubReserveTransferFee; - /// @dev extra fee to register an asset and discourage spamming - uint128 registerTokenFee; + /// @dev extra fee to register an asset and discourage spamming (Ether) + uint256 registerTokenFee; } // @dev Set token fees of the gateway @@ -486,7 +486,11 @@ contract Gateway is IGateway, IInitializable { } // Total fee for sending a token - function quoteSendTokenFee(address, ParaID destinationChain, uint128 destinationFee) external view returns (uint256) { + function quoteSendTokenFee(address, ParaID destinationChain, uint128 destinationFee) + external + view + returns (uint256) + { Costs memory costs = Assets.sendTokenCosts(ASSET_HUB_PARA_ID, destinationChain, destinationFee); return _calculateFee(costs); } diff --git a/parachain/pallets/control/src/benchmarking.rs b/parachain/pallets/control/src/benchmarking.rs index 394b66c3d9..e0962d81e0 100644 --- a/parachain/pallets/control/src/benchmarking.rs +++ b/parachain/pallets/control/src/benchmarking.rs @@ -7,7 +7,7 @@ use super::*; use crate::Pallet as SnowbridgeControl; use frame_benchmarking::v2::*; use frame_system::RawOrigin; -use snowbridge_core::outbound::OperatingMode; +use snowbridge_core::{eth, outbound::OperatingMode}; use sp_runtime::SaturatedConversion; use xcm::prelude::*; @@ -41,6 +41,24 @@ mod benchmarks { Ok(()) } + #[benchmark] + fn set_operating_mode() -> Result<(), BenchmarkError> { + #[extrinsic_call] + _(RawOrigin::Root, OperatingMode::RejectingOutboundMessages); + + Ok(()) + } + + #[benchmark] + fn set_pricing_parameters() -> Result<(), BenchmarkError> { + let params = T::DefaultPricingParameters::get(); + + #[extrinsic_call] + _(RawOrigin::Root, params); + + Ok(()) + } + #[benchmark] fn create_agent() -> Result<(), BenchmarkError> { let origin_para_id = 2000; @@ -101,14 +119,6 @@ mod benchmarks { Ok(()) } - #[benchmark] - fn set_operating_mode() -> Result<(), BenchmarkError> { - #[extrinsic_call] - _(RawOrigin::Root, OperatingMode::RejectingOutboundMessages); - - Ok(()) - } - #[benchmark] fn transfer_native_from_agent() -> Result<(), BenchmarkError> { let origin_para_id = 2000; @@ -139,5 +149,13 @@ mod benchmarks { Ok(()) } + #[benchmark] + fn set_token_transfer_fees() -> Result<(), BenchmarkError> { + #[extrinsic_call] + _(RawOrigin::Root, 1, 1, eth(1)); + + Ok(()) + } + impl_benchmark_test_suite!(SnowbridgeControl, crate::mock::new_test_ext(), crate::mock::Test); } diff --git a/parachain/pallets/control/src/lib.rs b/parachain/pallets/control/src/lib.rs index 1e89b09c55..0bf68887a0 100644 --- a/parachain/pallets/control/src/lib.rs +++ b/parachain/pallets/control/src/lib.rs @@ -62,6 +62,7 @@ use frame_support::{ }; use frame_system::pallet_prelude::*; use snowbridge_core::{ + meth, outbound::{Command, Initializer, Message, OperatingMode, SendError, SendMessage}, sibling_sovereign_account, AgentId, Channel, ChannelId, ParaId, PricingParameters as PricingParametersRecord, PRIMARY_GOVERNANCE_CHANNEL, @@ -128,6 +129,7 @@ where #[frame_support::pallet] pub mod pallet { use snowbridge_core::StaticLookup; + use sp_core::U256; use super::*; @@ -203,9 +205,9 @@ pub mod pallet { }, /// A SetTokenTransferFees message was sent to the Gateway SetTokenTransferFees { - create: u128, - transfer: u128, - register: u128, + create_asset_xcm: u128, + transfer_asset_xcm: u128, + register_token: U256, }, PricingParametersChanged { params: PricingParametersOf, @@ -337,6 +339,11 @@ pub mod pallet { Ok(()) } + /// Set pricing parameters on both sides of the bridge + /// + /// Fee required: No + /// + /// - `origin`: Must be root #[pallet::call_index(2)] #[pallet::weight((T::DbWeight::get().reads_writes(1, 1), DispatchClass::Operational))] pub fn set_pricing_parameters( @@ -551,34 +558,48 @@ pub mod pallet { ) } - /// Sends a message to the Gateway contract to set token transfer fees + /// Sends a message to the Gateway contract to update fee related parameters for + /// token transfers. /// /// Privileged. Can only be called by root. /// /// Fee required: No /// /// - `origin`: Must be root - /// - `register`: The fee for register token - /// - `send`: The fee for send token to parachain + /// - `create_asset_xcm`: The XCM execution cost for creating a new asset class on AssetHub, + /// in DOT + /// - `transfer_asset_xcm`: The XCM execution cost for performing a reserve transfer on + /// AssetHub, in DOT + /// - `register_token`: The Ether fee for registering a new token, to discourage spamming #[pallet::call_index(9)] #[pallet::weight(T::WeightInfo::set_token_transfer_fees())] pub fn set_token_transfer_fees( origin: OriginFor, - create: u128, - transfer: u128, - register: u128, + create_asset_xcm: u128, + transfer_asset_xcm: u128, + register_token: U256, ) -> DispatchResult { ensure_root(origin)?; + // Basic validation of new costs. Particularly for token registration, we want to ensure + // its relatively expensive to discourage spamming. Like at least 100 USD. ensure!( - create > 0 && transfer > 0 && register > 0, + create_asset_xcm > 0 && transfer_asset_xcm > 0 && register_token > meth(100), Error::::InvalidTokenTransferFees ); - let command = Command::SetTokenTransferFees { create, transfer, register }; + let command = Command::SetTokenTransferFees { + create_asset_xcm, + transfer_asset_xcm, + register_token, + }; Self::send(PRIMARY_GOVERNANCE_CHANNEL, command, PaysFee::::No)?; - Self::deposit_event(Event::::SetTokenTransferFees { register, create, transfer }); + Self::deposit_event(Event::::SetTokenTransferFees { + create_asset_xcm, + transfer_asset_xcm, + register_token, + }); Ok(()) } } diff --git a/parachain/pallets/control/src/tests.rs b/parachain/pallets/control/src/tests.rs index 25d17c5f0e..598f1e3cab 100644 --- a/parachain/pallets/control/src/tests.rs +++ b/parachain/pallets/control/src/tests.rs @@ -3,7 +3,7 @@ use crate::{mock::*, *}; use frame_support::{assert_noop, assert_ok}; use hex_literal::hex; -use snowbridge_core::sibling_sovereign_account_raw; +use snowbridge_core::{eth, sibling_sovereign_account_raw}; use sp_core::H256; use sp_runtime::{AccountId32, DispatchError::BadOrigin, TokenError}; @@ -123,6 +123,97 @@ fn upgrade_with_params() { }); } +#[test] +fn set_operating_mode() { + new_test_ext().execute_with(|| { + let origin = RuntimeOrigin::root(); + let mode = OperatingMode::RejectingOutboundMessages; + + assert_ok!(EthereumControl::set_operating_mode(origin, mode)); + + System::assert_last_event(RuntimeEvent::EthereumControl(crate::Event::SetOperatingMode { + mode, + })); + }); +} + +#[test] +fn set_operating_mode_as_signed_fails() { + new_test_ext().execute_with(|| { + let origin = RuntimeOrigin::signed([14; 32].into()); + let mode = OperatingMode::RejectingOutboundMessages; + + assert_noop!(EthereumControl::set_operating_mode(origin, mode), BadOrigin); + }); +} + +#[test] +fn set_pricing_parameters() { + new_test_ext().execute_with(|| { + let origin = RuntimeOrigin::root(); + let mut params = Parameters::get(); + params.rewards.local = 7; + + assert_ok!(EthereumControl::set_pricing_parameters(origin, params)); + + assert_eq!(PricingParameters::::get().rewards.local, 7); + }); +} + +#[test] +fn set_pricing_parameters_as_signed_fails() { + new_test_ext().execute_with(|| { + let origin = RuntimeOrigin::signed([14; 32].into()); + let params = Parameters::get(); + + assert_noop!(EthereumControl::set_pricing_parameters(origin, params), BadOrigin); + }); +} + +#[test] +fn set_pricing_parameters_invalid() { + new_test_ext().execute_with(|| { + let origin = RuntimeOrigin::root(); + let mut params = Parameters::get(); + params.rewards.local = 0; + + assert_noop!( + EthereumControl::set_pricing_parameters(origin, params), + Error::::InvalidPricingParameters + ); + }); +} + +#[test] +fn set_token_transfer_fees() { + new_test_ext().execute_with(|| { + let origin = RuntimeOrigin::root(); + + assert_ok!(EthereumControl::set_token_transfer_fees(origin, 1, 1, eth(1))); + }); +} + +#[test] +fn set_token_transfer_fees_root_only() { + new_test_ext().execute_with(|| { + let origin = RuntimeOrigin::signed([14; 32].into()); + + assert_noop!(EthereumControl::set_token_transfer_fees(origin, 1, 1, 1.into()), BadOrigin); + }); +} + +#[test] +fn set_token_transfer_fees_invalid() { + new_test_ext().execute_with(|| { + let origin = RuntimeOrigin::root(); + + assert_noop!( + EthereumControl::set_token_transfer_fees(origin, 0, 0, 0.into()), + Error::::InvalidTokenTransferFees + ); + }); +} + #[test] fn create_channel() { new_test_ext().execute_with(|| { @@ -358,30 +449,6 @@ fn force_update_channel_bad_origin() { }); } -#[test] -fn set_operating_mode_as_root() { - new_test_ext().execute_with(|| { - let origin = RuntimeOrigin::root(); - let mode = OperatingMode::RejectingOutboundMessages; - - assert_ok!(EthereumControl::set_operating_mode(origin, mode)); - - System::assert_last_event(RuntimeEvent::EthereumControl(crate::Event::SetOperatingMode { - mode, - })); - }); -} - -#[test] -fn set_operating_mode_as_signed_fails() { - new_test_ext().execute_with(|| { - let origin = RuntimeOrigin::signed([14; 32].into()); - let mode = OperatingMode::RejectingOutboundMessages; - - assert_noop!(EthereumControl::set_operating_mode(origin, mode), BadOrigin); - }); -} - #[test] fn transfer_native_from_agent() { new_test_ext().execute_with(|| { @@ -558,27 +625,3 @@ fn charge_fee_for_upgrade() { assert_eq!(sovereign_balance, InitialFunding::get()); }); } - -#[test] -fn set_pricing_params_root_only() { - new_test_ext().execute_with(|| { - let origin = RuntimeOrigin::signed(AccountId32::from([0; 32])); - assert_noop!( - EthereumControl::set_pricing_parameters(origin, Parameters::get()), - DispatchError::BadOrigin, - ); - }) -} - -#[test] -fn set_fee_config_invalid() { - new_test_ext().execute_with(|| { - let origin = RuntimeOrigin::root(); - let mut params = Parameters::get(); - params.rewards.local = 0; - assert_noop!( - EthereumControl::set_pricing_parameters(origin, params), - Error::::InvalidPricingParameters - ); - }) -} diff --git a/parachain/pallets/control/src/weights.rs b/parachain/pallets/control/src/weights.rs index 70166ad06e..5cc70e51b2 100644 --- a/parachain/pallets/control/src/weights.rs +++ b/parachain/pallets/control/src/weights.rs @@ -41,6 +41,7 @@ pub trait WeightInfo { fn transfer_native_from_agent() -> Weight; fn force_transfer_native_from_agent() -> Weight; fn set_token_transfer_fees() -> Weight; + fn set_pricing_parameters() -> Weight; } // For backwards compatibility and tests. @@ -225,4 +226,24 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } + + /// Storage: ParachainInfo ParachainId (r:1 w:0) + /// Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: EthereumOutboundQueue PalletOperatingMode (r:1 w:0) + /// Proof: EthereumOutboundQueue PalletOperatingMode (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:1 w:1) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:1) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:0 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn set_pricing_parameters() -> Weight { + // Proof Size summary in bytes: + // Measured: `80` + // Estimated: `3517` + // Minimum execution time: 31_000_000 picoseconds. + Weight::from_parts(42_000_000, 3517) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } } diff --git a/parachain/primitives/core/src/outbound.rs b/parachain/primitives/core/src/outbound.rs index 28dc399aae..6c440bbe1f 100644 --- a/parachain/primitives/core/src/outbound.rs +++ b/parachain/primitives/core/src/outbound.rs @@ -119,15 +119,15 @@ mod v1 { /// Set token fees of the Gateway contract SetTokenTransferFees { /// The fee(DOT) for the cost of creating asset on AssetHub - create: u128, + create_asset_xcm: u128, /// The fee(DOT) for the cost of sending asset on AssetHub - transfer: u128, - /// The fee(Ether) for register an asset with reserve deposit and discourage spamming - register: u128, + transfer_asset_xcm: u128, + /// The fee(Ether) for register token to discourage spamming + register_token: U256, }, /// Set pricing parameters SetPricingParameters { - // relative ETH value + // ETH/DOT exchange rate exchange_rate: UD60x18, // Cost of delivering a message from Ethereum to BridgeHub, in ROC/KSM/DOT delivery_cost: u128, @@ -189,12 +189,15 @@ mod v1 { Token::Address(*recipient), Token::Uint(U256::from(*amount)), ])]), - Command::SetTokenTransferFees { create, transfer, register } => - ethabi::encode(&[Token::Tuple(vec![ - Token::Uint(U256::from(*create)), - Token::Uint(U256::from(*transfer)), - Token::Uint(U256::from(*register)), - ])]), + Command::SetTokenTransferFees { + create_asset_xcm, + transfer_asset_xcm, + register_token, + } => ethabi::encode(&[Token::Tuple(vec![ + Token::Uint(U256::from(*create_asset_xcm)), + Token::Uint(U256::from(*transfer_asset_xcm)), + Token::Uint(*register_token), + ])]), Command::SetPricingParameters { exchange_rate, delivery_cost } => ethabi::encode(&[Token::Tuple(vec![ Token::Uint(exchange_rate.clone().into_inner()), From 359784e858a94de215213f18aa61083675295577 Mon Sep 17 00:00:00 2001 From: Vincent Geddes Date: Wed, 29 Nov 2023 21:34:13 +0200 Subject: [PATCH 36/38] Bump polkadot-sdk --- polkadot-sdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polkadot-sdk b/polkadot-sdk index 21cf8340f5..e01068d91b 160000 --- a/polkadot-sdk +++ b/polkadot-sdk @@ -1 +1 @@ -Subproject commit 21cf8340f5a4c233ad6e58373ac245c4766b737e +Subproject commit e01068d91b086455f4e21835ce7a0e95cdc89fd9 From c0b32eeccf3817755edd18df4b1362283fcfbe8c Mon Sep 17 00:00:00 2001 From: ron Date: Thu, 30 Nov 2023 16:17:51 +0800 Subject: [PATCH 37/38] Refactor convertToNative logic --- contracts/src/DeployScript.sol | 8 +++----- contracts/src/Gateway.sol | 10 ++++++---- contracts/test/Gateway.t.sol | 8 +++----- contracts/test/mocks/GatewayMock.sol | 4 ++-- web/packages/test/scripts/set-env.sh | 5 ++--- 5 files changed, 16 insertions(+), 19 deletions(-) diff --git a/contracts/src/DeployScript.sol b/contracts/src/DeployScript.sol index f7f9fde300..ef0583951a 100644 --- a/contracts/src/DeployScript.sol +++ b/contracts/src/DeployScript.sol @@ -15,14 +15,12 @@ import {AgentExecutor} from "./AgentExecutor.sol"; import {ChannelID, ParaID, OperatingMode} from "./Types.sol"; import {SafeNativeTransfer} from "./utils/SafeTransfer.sol"; import {stdJson} from "forge-std/StdJson.sol"; -import {UD60x18, ud60x18, convert} from "prb/math/src/UD60x18.sol"; +import {UD60x18, ud60x18} from "prb/math/src/UD60x18.sol"; contract DeployScript is Script { using SafeNativeTransfer for address payable; using stdJson for string; - UD60x18 internal dotToEthDecimals; - function setUp() public {} function run() public { @@ -59,7 +57,7 @@ contract DeployScript is Script { ParaID assetHubParaID = ParaID.wrap(uint32(vm.envUint("ASSET_HUB_PARAID"))); bytes32 assetHubAgentID = vm.envBytes32("ASSET_HUB_AGENT_ID"); - dotToEthDecimals = convert(vm.envUint("DOT_TO_ETH_DECIMALS")); + uint8 foreignTokenDecimals = uint8(vm.envUint("FOREIGN_TOKEN_DECIMALS")); AgentExecutor executor = new AgentExecutor(); Gateway gatewayLogic = new Gateway( @@ -69,7 +67,7 @@ contract DeployScript is Script { bridgeHubAgentID, assetHubParaID, assetHubAgentID, - dotToEthDecimals + foreignTokenDecimals ); bool rejectOutboundMessages = vm.envBool("REJECT_OUTBOUND_MESSAGES"); diff --git a/contracts/src/Gateway.sol b/contracts/src/Gateway.sol index 484922e59e..bf40f17419 100644 --- a/contracts/src/Gateway.sol +++ b/contracts/src/Gateway.sol @@ -65,7 +65,7 @@ contract Gateway is IGateway, IInitializable { // 2. Calling implementation function uint256 DISPATCH_OVERHEAD_GAS = 10_000; - UD60x18 internal immutable DOT_TO_ETH_DECIMALS; + uint8 internal immutable FOREIGN_TOKEN_DECIMALS; error InvalidProof(); error InvalidNonce(); @@ -98,7 +98,7 @@ contract Gateway is IGateway, IInitializable { bytes32 bridgeHubAgentID, ParaID assetHubParaID, bytes32 assetHubAgentID, - UD60x18 dotToEthDecimals + uint8 foreignTokenDecimals ) { if ( bridgeHubParaID == ParaID.wrap(0) || bridgeHubAgentID == 0 || assetHubParaID == ParaID.wrap(0) @@ -114,7 +114,7 @@ contract Gateway is IGateway, IInitializable { BRIDGE_HUB_AGENT_ID = bridgeHubAgentID; ASSET_HUB_PARA_ID = assetHubParaID; ASSET_HUB_AGENT_ID = assetHubAgentID; - DOT_TO_ETH_DECIMALS = dotToEthDecimals; + FOREIGN_TOKEN_DECIMALS = foreignTokenDecimals; } /// @dev Submit a message from Polkadot for verification and dispatch @@ -535,7 +535,9 @@ contract Gateway is IGateway, IInitializable { // Convert foreign currency to native currency (ROC/KSM/DOT -> ETH) function _convertToNative(UD60x18 exchangeRate, uint256 amount) internal view returns (uint256) { UD60x18 amountFP = convert(amount); - UD60x18 nativeAmountFP = amountFP.mul(exchangeRate).mul(DOT_TO_ETH_DECIMALS); + UD60x18 ethDecimals = convert(1e18); + UD60x18 foreignDecimals = convert(10).pow(convert(uint256(FOREIGN_TOKEN_DECIMALS))); + UD60x18 nativeAmountFP = amountFP.mul(exchangeRate).div(foreignDecimals).mul(ethDecimals); uint256 nativeAmount = convert(nativeAmountFP); return nativeAmount; } diff --git a/contracts/test/Gateway.t.sol b/contracts/test/Gateway.t.sol index 250e9b945a..b177b9d7ca 100644 --- a/contracts/test/Gateway.t.sol +++ b/contracts/test/Gateway.t.sol @@ -73,10 +73,8 @@ contract GatewayTest is Test { MultiAddress public recipientAddress32; MultiAddress public recipientAddress20; - // DOT amounts need to be multiplied by 10^(18 - 10) to have the same number - // decimal places as ETH (18 decimal places) - // UD60x18.convert(1e8) == ud60x18(1e26) - UD60x18 public dotToEthDecimals = ud60x18(1e26); + // For DOT + uint8 public foreignTokenDecimals = 10; // ETH/DOT exchange rate UD60x18 public exchangeRate = ud60x18(0.0025e18); @@ -90,7 +88,7 @@ contract GatewayTest is Test { bridgeHubAgentID, assetHubParaID, assetHubAgentID, - dotToEthDecimals + foreignTokenDecimals ); Gateway.Config memory config = Gateway.Config({ mode: OperatingMode.Normal, diff --git a/contracts/test/mocks/GatewayMock.sol b/contracts/test/mocks/GatewayMock.sol index c2d7bbc5f8..cabd952e98 100644 --- a/contracts/test/mocks/GatewayMock.sol +++ b/contracts/test/mocks/GatewayMock.sol @@ -18,7 +18,7 @@ contract GatewayMock is Gateway { bytes32 bridgeHubHubAgentID, ParaID assetHubParaID, bytes32 assetHubHubAgentID, - UD60x18 dotToEthDecimals + uint8 foreignTokenDecimals ) Gateway( beefyClient, @@ -27,7 +27,7 @@ contract GatewayMock is Gateway { bridgeHubHubAgentID, assetHubParaID, assetHubHubAgentID, - dotToEthDecimals + foreignTokenDecimals ) {} diff --git a/web/packages/test/scripts/set-env.sh b/web/packages/test/scripts/set-env.sh index 07b6c88fb2..f3a7c95ffe 100755 --- a/web/packages/test/scripts/set-env.sh +++ b/web/packages/test/scripts/set-env.sh @@ -48,9 +48,8 @@ export PENPAL_CHANNEL_ID="0xa69fbbae90bb6096d59b1930bbcfc8a3ef23959d226b1861deb7 export PRIMARY_GOVERNANCE_CHANNEL_ID="0x0000000000000000000000000000000000000000000000000000000000000001" export SECONDARY_GOVERNANCE_CHANNEL_ID="0x0000000000000000000000000000000000000000000000000000000000000002" -# ROC and KSM amounts need to be multiplied by 10^(18 - 12) to have the same number -# of decimal places as ETH (18 decimal places) -export DOT_TO_ETH_DECIMALS=1000000 +# Token decimal of the relaychain(KSM|ROC:12,DOT:10) +export FOREIGN_TOKEN_DECIMALS=12 relaychain_ws_url="${RELAYCHAIN_WS_URL:-ws://127.0.0.1:9944}" relaychain_sudo_seed="${RELAYCHAIN_SUDO_SEED:-//Alice}" From 770c965adfcad5c00e1be117d515df890783f154 Mon Sep 17 00:00:00 2001 From: Vincent Geddes Date: Thu, 30 Nov 2023 11:18:53 +0200 Subject: [PATCH 38/38] Update polkadot-sdk --- polkadot-sdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polkadot-sdk b/polkadot-sdk index e01068d91b..27c82f9d86 160000 --- a/polkadot-sdk +++ b/polkadot-sdk @@ -1 +1 @@ -Subproject commit e01068d91b086455f4e21835ce7a0e95cdc89fd9 +Subproject commit 27c82f9d860e608e256d2bd68e91a8e658cb5734