Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SNO-624: Charge fee for outbound operations #940

Closed
wants to merge 80 commits into from
Closed
Show file tree
Hide file tree
Changes from 79 commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
fe22333
Support reserve deposit for control operations
yrong Aug 29, 2023
2d28b2b
Pay as agent_owner
yrong Aug 29, 2023
ffa44a7
Add AgentAccountDescription converter
yrong Aug 31, 2023
80a750c
Merge branch 'main' into ron/oak-sno-624
yrong Aug 31, 2023
33f6ab8
Revamp smoke test config fee for control operations
yrong Aug 31, 2023
6cc82e5
Add SovereignAccountOf to runtime config
yrong Aug 31, 2023
3e5e9ff
Merge branch 'main' into ron/oak-sno-624
yrong Sep 4, 2023
e9be7d4
Fix format
yrong Sep 4, 2023
e2946ee
More refactor
yrong Sep 4, 2023
cb6f6aa
Configurable base fee plus static per-operation fee multiplier
yrong Sep 5, 2023
614e429
Update smoke test accordingly
yrong Sep 5, 2023
ec7814b
Update cumulus
yrong Sep 5, 2023
2f939cd
Merge branch 'main' into ron/oak-sno-624
yrong Sep 7, 2023
e777666
Fix format
yrong Sep 7, 2023
8830961
Merge branch 'main' into ron/oak-sno-624
yrong Sep 11, 2023
3fef8b4
Configurable dispatch_gas
yrong Sep 12, 2023
d02f041
Update relayer
yrong Sep 12, 2023
aac06fc
Merge branch 'ron/oak-23' into ron/oak-sno-624
yrong Sep 12, 2023
353c21e
Refactor to charge fee for outbound commands
yrong Sep 13, 2023
7caed3e
More refactor
yrong Sep 13, 2023
77ebfb6
Update cargo.lock
yrong Sep 13, 2023
1694b38
Chore
yrong Sep 13, 2023
58fa4d7
Fix clippy
yrong Sep 13, 2023
82d2ed5
Chore format
yrong Sep 13, 2023
aca2309
Update cumulus
yrong Sep 13, 2023
0b1d744
Reward message relayer
yrong Sep 13, 2023
6aa80cc
Fix smoke tests
yrong Sep 13, 2023
755d50f
Set default dispatch gas
yrong Sep 14, 2023
63b7221
Fix for origin of control operations & Charge fee without gas cost
yrong Sep 14, 2023
a473f06
Update parachain/pallets/outbound-queue/src/lib.rs
yrong Sep 14, 2023
50a0b79
Update parachain/pallets/outbound-queue/src/lib.rs
yrong Sep 14, 2023
c834c49
Specify the fee for xcm export & upfront charge for create_agent only
yrong Sep 14, 2023
b3522cd
Remove deprecated config
yrong Sep 15, 2023
b6abf68
Fix format
yrong Sep 15, 2023
f976e1e
Set decent default for outbound configs
yrong Sep 15, 2023
16f89d2
Make create-channel upfront charged & start template relayer for othe…
yrong Sep 15, 2023
febc0a1
Disable base fee for sudo operations
yrong Sep 15, 2023
7477cc1
Merge branch 'main' into ron/oak-sno-624
yrong Sep 15, 2023
5fbbfb9
Update gas cost
yrong Sep 18, 2023
86c3ffc
Fix cargo tarpaulin
yrong Sep 18, 2023
dc4d898
Update cumulus
yrong Sep 22, 2023
0c4921c
Update cumulus
yrong Sep 22, 2023
3b784b2
Add OutboundFeeConfig
yrong Sep 22, 2023
4399ed0
Fund template sovereign account
yrong Sep 22, 2023
b477887
Rename as agent_location
yrong Sep 22, 2023
8870326
Fix clippy
yrong Sep 22, 2023
460e10d
Validate ticket with gas check
yrong Sep 22, 2023
448963a
Move the charge logic to control pallet & More refactor
yrong Sep 22, 2023
e8308f8
Fix clippy
yrong Sep 22, 2023
9d2594c
Disable format temporarily for less distraction
yrong Sep 22, 2023
f2350c1
Refactor estimate by message
yrong Sep 22, 2023
19e03e7
More refactor
yrong Sep 23, 2023
24e1ec1
Fix clippy
yrong Sep 23, 2023
8fbb705
More cleanup
yrong Sep 26, 2023
f531c71
Fix test & Remove format
yrong Sep 26, 2023
7bfae29
Add estimate rpc
yrong Sep 26, 2023
3175e02
Estimate by command index & Add smoke test accordingly
yrong Sep 27, 2023
0e61abe
Fix upgrade test
yrong Sep 27, 2023
1d160b0
Initialize with more funds & Add script for fund
yrong Sep 27, 2023
8455abc
Update contracts/test/Gateway.t.sol
yrong Sep 27, 2023
b46f889
Rename event as OutboundFeeConfigUpdated
yrong Sep 27, 2023
98aafba
Merge branch 'ron/oak-sno-624' of https://github.com/Snowfork/snowbri…
yrong Sep 27, 2023
6aed8d0
For comment
yrong Sep 27, 2023
c8cd91e
Chore
yrong Sep 27, 2023
309ce5a
Refactor with structured OriginInfo
yrong Sep 27, 2023
4a8730d
Clean derive macros
yrong Sep 27, 2023
dd6a21f
Leave enough space for upgrade
yrong Sep 27, 2023
a6649d8
Runtime api for compute_fee_reward
yrong Sep 27, 2023
6dfe502
Use TreasuryAccount more specific
yrong Sep 28, 2023
aab0ec0
Improve comments
yrong Sep 28, 2023
2db5125
Improve smoke test
yrong Sep 28, 2023
d8ced19
Update smoketest/src/helper.rs
yrong Sep 28, 2023
cde7c8d
Update smoketest/src/helper.rs
yrong Sep 28, 2023
9d99217
Some cleanup
yrong Sep 28, 2023
586b8b8
Update cumulus
yrong Sep 28, 2023
ef3395e
Merge branch 'ron/oak-sno-624' of https://github.com/Snowfork/snowbri…
yrong Sep 28, 2023
378ca74
Test for fee with config changed
yrong Sep 28, 2023
9a905a4
A thin shell wrapper funding agent
yrong Sep 28, 2023
05abc2c
More tests
yrong Sep 28, 2023
584ba51
Update parachain/pallets/outbound-queue/src/test.rs
yrong Sep 29, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions .github/workflows/parachain.yml
Original file line number Diff line number Diff line change
Expand Up @@ -113,14 +113,12 @@ jobs:
run: rustup show
- name: run coverage test
run: >
cargo install cargo-tarpaulin &&
cargo install cargo-tarpaulin@0.27.0 &&
cargo tarpaulin
--manifest-path parachain/Cargo.toml
--workspace
--engine llvm
--out Xml
--exclude substrate-call-index
--exclude snowbridge-query-events
--out xml
- name: Upload coverage reports to Codecov with GitHub Action
uses: codecov/codecov-action@v3
with:
Expand All @@ -133,7 +131,7 @@ jobs:
steps:
- uses: actions/checkout@v2
with:
submodules: 'true'
submodules: "true"
- uses: arduino/setup-protoc@v2
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
Expand Down
6 changes: 1 addition & 5 deletions contracts/src/DeployScript.sol
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ contract DeployScript is Script {
Gateway gatewayLogic = new Gateway(
address(beefyClient),
address(executor),
vm.envUint("DISPATCH_GAS"),
bridgeHubParaID,
bridgeHubAgentID,
assetHubParaID,
Expand All @@ -59,10 +58,7 @@ contract DeployScript is Script {
);

bytes memory initParams = abi.encode(
vm.envUint("DEFAULT_FEE"),
vm.envUint("DEFAULT_REWARD"),
vm.envUint("REGISTER_NATIVE_TOKEN_FEE"),
vm.envUint("SEND_NATIVE_TOKEN_FEE")
vm.envUint("DEFAULT_FEE"), vm.envUint("REGISTER_NATIVE_TOKEN_FEE"), vm.envUint("SEND_NATIVE_TOKEN_FEE")
);

GatewayProxy gateway = new GatewayProxy(address(gatewayLogic), initParams);
Expand Down
46 changes: 46 additions & 0 deletions contracts/src/FundAgent.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <hello@snowfork.com>
pragma solidity 0.8.20;

import {WETH9} from "canonical-weth/WETH9.sol";
import {Script} from "forge-std/Script.sol";
import {BeefyClient} from "./BeefyClient.sol";

import {IGateway} from "./interfaces/IGateway.sol";
import {GatewayProxy} from "./GatewayProxy.sol";
import {Gateway} from "./Gateway.sol";
import {GatewayUpgradeMock} from "../test/mocks/GatewayUpgradeMock.sol";
import {Agent} from "./Agent.sol";
import {AgentExecutor} from "./AgentExecutor.sol";
import {ParaID, Config} from "./Types.sol";
import {SafeNativeTransfer} from "./utils/SafeTransfer.sol";
import {stdJson} from "forge-std/StdJson.sol";

contract FundAgent is Script {
using SafeNativeTransfer for address payable;
using stdJson for string;

function setUp() public {}

function run() public {
uint256 privateKey = vm.envUint("PRIVATE_KEY");
address deployer = vm.rememberKey(privateKey);
vm.startBroadcast(deployer);

uint256 initialDeposit = vm.envUint("BRIDGE_HUB_INITIAL_DEPOSIT");
claravanstaden marked this conversation as resolved.
Show resolved Hide resolved
address gatewayAddress = vm.envAddress("GATEWAY_PROXY_CONTRACT");

ParaID bridgeHubParaID = ParaID.wrap(vm.envUint("BRIDGE_HUB_PARAID"));
bytes32 bridgeHubAgentID = vm.envBytes32("BRIDGE_HUB_AGENT_ID");
ParaID assetHubParaID = ParaID.wrap(vm.envUint("ASSET_HUB_PARAID"));
bytes32 assetHubAgentID = vm.envBytes32("ASSET_HUB_AGENT_ID");

address bridgeHubAgent = IGateway(gatewayAddress).agentOf(bridgeHubAgentID);
address assetHubAgent = IGateway(gatewayAddress).agentOf(assetHubAgentID);

payable(bridgeHubAgent).safeNativeTransfer(initialDeposit);
payable(assetHubAgent).safeNativeTransfer(initialDeposit);

vm.stopBroadcast();
}
}
46 changes: 19 additions & 27 deletions contracts/src/Gateway.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ contract Gateway is IGateway, IInitializable {

// After message dispatch, there should be some gas left over for post dispatch logic
uint256 internal constant BUFFER_GAS = 32_000;
uint256 internal immutable DISPATCH_GAS;
address internal immutable AGENT_EXECUTOR;

// Verification state
Expand Down Expand Up @@ -69,24 +68,21 @@ contract Gateway is IGateway, IInitializable {
constructor(
address beefyClient,
address agentExecutor,
uint256 dispatchGas,
ParaID bridgeHubParaID,
bytes32 bridgeHubAgentID,
ParaID assetHubParaID,
bytes32 assetHubAgentID,
bytes2 createTokenCallID
) {
if (
dispatchGas == 0 || bridgeHubParaID == ParaID.wrap(0) || bridgeHubAgentID == 0
|| assetHubParaID == ParaID.wrap(0) || assetHubAgentID == 0 || bridgeHubParaID == assetHubParaID
|| bridgeHubAgentID == assetHubAgentID
bridgeHubParaID == ParaID.wrap(0) || bridgeHubAgentID == 0 || assetHubParaID == ParaID.wrap(0)
|| assetHubAgentID == 0 || bridgeHubParaID == assetHubParaID || bridgeHubAgentID == assetHubAgentID
) {
revert InvalidConstructorParams();
}

BEEFY_CLIENT = beefyClient;
AGENT_EXECUTOR = agentExecutor;
DISPATCH_GAS = dispatchGas;
BRIDGE_HUB_PARA_ID_ENCODED = ScaleCodec.encodeU32(uint32(ParaID.unwrap(bridgeHubParaID)));
BRIDGE_HUB_PARA_ID = bridgeHubParaID;
BRIDGE_HUB_AGENT_ID = bridgeHubAgentID;
Expand Down Expand Up @@ -119,8 +115,8 @@ contract Gateway is IGateway, IInitializable {
// Reward the relayer from the agent contract
// Expected to revert if the agent for the message origin does not have enough funds to reward the relayer.
// In that case, the origin should top up the funds of their agent.
if (channel.reward > 0) {
_transferNativeFromAgent(channel.agent, payable(msg.sender), channel.reward);
if (message.reward > 0) {
_transferNativeFromAgent(channel.agent, payable(msg.sender), message.reward);
}

// Produce the commitment (message root) by applying the leaf proof to the message leaf
Expand All @@ -136,45 +132,46 @@ contract Gateway is IGateway, IInitializable {
// Otherwise malicious relayers can break the bridge by allowing the message handlers below to run out gas and fail silently.
// In this scenario case, the channel's state would have been updated to accept the message (by virtue of the nonce increment), yet the actual message
// dispatch would have failed
if (gasleft() < DISPATCH_GAS + BUFFER_GAS) {
uint256 dispatchGas = message.dispatchGas;
if (gasleft() < dispatchGas + BUFFER_GAS) {
yrong marked this conversation as resolved.
Show resolved Hide resolved
revert NotEnoughGas();
}

bool success = true;

// Dispatch message to a handler
if (message.command == Command.AgentExecute) {
try Gateway(this).agentExecute{gas: DISPATCH_GAS}(message.params) {}
try Gateway(this).agentExecute{gas: dispatchGas}(message.params) {}
catch {
success = false;
}
} else if (message.command == Command.CreateAgent) {
try Gateway(this).createAgent{gas: DISPATCH_GAS}(message.params) {}
try Gateway(this).createAgent{gas: dispatchGas}(message.params) {}
catch {
success = false;
}
} else if (message.command == Command.CreateChannel) {
try Gateway(this).createChannel{gas: DISPATCH_GAS}(message.params) {}
try Gateway(this).createChannel{gas: dispatchGas}(message.params) {}
catch {
success = false;
}
} else if (message.command == Command.UpdateChannel) {
try Gateway(this).updateChannel{gas: DISPATCH_GAS}(message.params) {}
try Gateway(this).updateChannel{gas: dispatchGas}(message.params) {}
catch {
success = false;
}
} else if (message.command == Command.SetOperatingMode) {
try Gateway(this).setOperatingMode{gas: DISPATCH_GAS}(message.params) {}
try Gateway(this).setOperatingMode{gas: dispatchGas}(message.params) {}
catch {
success = false;
}
} else if (message.command == Command.TransferNativeFromAgent) {
try Gateway(this).transferNativeFromAgent{gas: DISPATCH_GAS}(message.params) {}
try Gateway(this).transferNativeFromAgent{gas: dispatchGas}(message.params) {}
catch {
success = false;
}
} else if (message.command == Command.Upgrade) {
try Gateway(this).upgrade{gas: DISPATCH_GAS}(message.params) {}
try Gateway(this).upgrade{gas: dispatchGas}(message.params) {}
catch {
success = false;
}
Expand All @@ -201,9 +198,9 @@ contract Gateway is IGateway, IInitializable {
return (ch.inboundNonce, ch.outboundNonce);
}

function channelFeeRewardOf(ParaID paraID) external view returns (uint256, uint256) {
function channelFeeOf(ParaID paraID) external view returns (uint256) {
Channel storage ch = _ensureChannel(paraID);
return (ch.fee, ch.reward);
return ch.fee;
}

function agentOf(bytes32 agentID) external view returns (address) {
Expand Down Expand Up @@ -291,7 +288,6 @@ contract Gateway is IGateway, IInitializable {
ch.inboundNonce = 0;
ch.outboundNonce = 0;
ch.fee = $.defaultFee;
ch.reward = $.defaultReward;

emit ChannelCreated(params.paraID);
}
Expand Down Expand Up @@ -324,7 +320,6 @@ contract Gateway is IGateway, IInitializable {

ch.mode = params.mode;
ch.fee = params.fee;
ch.reward = params.reward;

emit ChannelUpdated(params.paraID);
}
Expand Down Expand Up @@ -529,14 +524,13 @@ contract Gateway is IGateway, IInitializable {
revert Unauthorized();
}

(uint256 defaultFee, uint256 defaultReward, uint256 registerTokenFee, uint256 sendTokenFee) =
abi.decode(data, (uint256, uint256, uint256, uint256));
(uint256 defaultFee, uint256 registerTokenFee, uint256 sendTokenFee) =
abi.decode(data, (uint256, uint256, uint256));

CoreStorage.Layout storage $ = CoreStorage.layout();

$.mode = OperatingMode.Normal;
$.defaultFee = defaultFee;
$.defaultReward = defaultReward;

// Initialize an agent & channel for BridgeHub
address bridgeHubAgent = address(new Agent(BRIDGE_HUB_AGENT_ID));
Expand All @@ -546,8 +540,7 @@ contract Gateway is IGateway, IInitializable {
agent: bridgeHubAgent,
inboundNonce: 0,
outboundNonce: 0,
fee: defaultFee,
reward: defaultReward
fee: defaultFee
});

// Initialize an agent & channel for AssetHub
Expand All @@ -558,8 +551,7 @@ contract Gateway is IGateway, IInitializable {
agent: assetHubAgent,
inboundNonce: 0,
outboundNonce: 0,
fee: defaultFee,
reward: defaultReward
fee: defaultFee
});

Assets.initialize(registerTokenFee, sendTokenFee);
Expand Down
6 changes: 4 additions & 2 deletions contracts/src/Types.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ struct Channel {
address agent;
/// @dev The fee charged to users for submitting outbound messages
uint256 fee;
/// @dev The reward disbursed to message relayers for submitting inbound messages
uint256 reward;
}

/// @dev Inbound message from a Polkadot parachain (via BridgeHub)
Expand All @@ -41,6 +39,10 @@ struct InboundMessage {
Command command;
/// @dev The Parameters for the command
bytes params;
/// @dev The maximum gas allowed for message dispatch
uint256 dispatchGas;
/// @dev The reward in ether for delivering this message
uint256 reward;
}

enum OperatingMode {
Expand Down
2 changes: 1 addition & 1 deletion contracts/src/interfaces/IGateway.sol
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ interface IGateway {

function operatingMode() external view returns (OperatingMode);
function channelOperatingModeOf(ParaID paraID) external view returns (OperatingMode);
function channelFeeRewardOf(ParaID paraID) external view returns (uint256, uint256);
function channelFeeOf(ParaID paraID) external view returns (uint256);
function channelNoncesOf(ParaID paraID) external view returns (uint64, uint64);
function agentOf(bytes32 agentID) external view returns (address);
function implementation() external view returns (address);
Expand Down
2 changes: 0 additions & 2 deletions contracts/src/storage/CoreStorage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ library CoreStorage {
mapping(bytes32 agentID => address) agents;
// The default fee charged to users for submitting outbound message to Polkadot
uint256 defaultFee;
// The default reward given to relayers for submitting inbound messages from Polkadot
uint256 defaultReward;
}

bytes32 internal constant SLOT = keccak256("org.snowbridge.storage.core");
Expand Down
Loading