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

Add command to update registerTokenFee and sendTokenFee #991

Merged
merged 15 commits into from
Nov 9, 2023
Merged
23 changes: 22 additions & 1 deletion contracts/src/Gateway.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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, InboundMessage, OperatingMode, ParaID, Config, Command} from "./Types.sol";
import {Channel, InboundMessage, OperatingMode, ParaID, Config, Command, AssetFees} from "./Types.sol";
vgeddes marked this conversation as resolved.
Show resolved Hide resolved
import {IGateway} from "./interfaces/IGateway.sol";
import {IInitializable} from "./interfaces/IInitializable.sol";
import {ERC1967} from "./utils/ERC1967.sol";
Expand Down Expand Up @@ -173,6 +173,11 @@ contract Gateway is IGateway, IInitializable {
catch {
success = false;
}
} else if (message.command == Command.UpdateFees) {
try Gateway(this).updateFees{gas: maxDispatchGas}(message.params) {}
catch {
success = false;
}
}

// Calculate the actual cost of executing this message
Expand Down Expand Up @@ -230,6 +235,13 @@ contract Gateway is IGateway, IInitializable {
return ERC1967.load();
}

function assetFees() external view returns (AssetFees memory fees) {
AssetsStorage.Layout storage $ = AssetsStorage.layout();
fees.register = $.registerTokenFee;
fees.send = $.sendTokenFee;
return fees;
}

/**
* Handlers
*/
Expand Down Expand Up @@ -411,6 +423,15 @@ contract Gateway is IGateway, IInitializable {
emit AgentFundsWithdrawn(params.agentID, params.recipient, params.amount);
}

// @dev Set the operating mode of the gateway
function updateFees(bytes calldata data) external onlySelf {
AssetsStorage.Layout storage $ = AssetsStorage.layout();
AssetFees memory params = abi.decode(data, (AssetFees));
$.registerTokenFee = params.register;
$.sendTokenFee = params.send;
emit FeeUpdated(params.register, params.send);
}

/**
* Assets
*/
Expand Down
10 changes: 9 additions & 1 deletion contracts/src/Types.sol
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,15 @@ enum Command {
CreateChannel,
UpdateChannel,
SetOperatingMode,
TransferNativeFromAgent
TransferNativeFromAgent,
UpdateFees
yrong marked this conversation as resolved.
Show resolved Hide resolved
}

enum AgentExecuteCommand {TransferToken}

struct AssetFees {
/// @dev register token
uint256 register;
/// @dev send token to parachain
uint256 send;
}
6 changes: 5 additions & 1 deletion contracts/src/interfaces/IGateway.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// SPDX-FileCopyrightText: 2023 Snowfork <[email protected]>
pragma solidity 0.8.20;

import {OperatingMode, InboundMessage, ParaID} from "../Types.sol";
import {OperatingMode, InboundMessage, ParaID, AssetFees} from "../Types.sol";
import {Verification} from "../Verification.sol";

interface IGateway {
Expand Down Expand Up @@ -34,6 +34,9 @@ interface IGateway {
// Emitted when funds are withdrawn from an agent
event AgentFundsWithdrawn(bytes32 indexed agentID, address indexed recipient, uint256 amount);

// Emitted when the fees updated
event FeeUpdated(uint256 register, uint256 send);

/**
* Getters
*/
Expand All @@ -44,6 +47,7 @@ interface IGateway {
function channelNoncesOf(ParaID paraID) external view returns (uint64, uint64);
function agentOf(bytes32 agentID) external view returns (address);
function implementation() external view returns (address);
function assetFees() external view returns (AssetFees memory);

/**
* Messaging
Expand Down
11 changes: 10 additions & 1 deletion contracts/test/Gateway.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ import {SubstrateTypes} from "./../src/SubstrateTypes.sol";

import {NativeTransferFailed} from "../src/utils/SafeTransfer.sol";

import {AgentExecuteCommand, InboundMessage, OperatingMode, ParaID, Config, Command} from "../src/Types.sol";
import {
AgentExecuteCommand, InboundMessage, OperatingMode, ParaID, Config, Command, AssetFees
} from "../src/Types.sol";

import {WETH9} from "canonical-weth/WETH9.sol";
import "./mocks/GatewayUpgradeMock.sol";
Expand Down Expand Up @@ -747,4 +749,11 @@ contract GatewayTest is Test {
InboundMessage(bridgeHubParaID, 1, command, params, 1, maxRefund, reward), proof, makeMockProof()
);
}

function testSetFees() public {
GatewayMock(address(gateway)).updateFeesPublic(abi.encode(AssetFees({register: 1, send: 1})));
AssetFees memory fees = IGateway(address(gateway)).assetFees();
assertEq(fees.register, 1);
assertEq(fees.send, 1);
}
}
4 changes: 4 additions & 0 deletions contracts/test/mocks/GatewayMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ contract GatewayMock is Gateway {
return commitmentsAreVerified;
}
}

function updateFeesPublic(bytes calldata params) external {
this.updateFees(params);
}
}

library AdditionalStorage {
Expand Down
6 changes: 5 additions & 1 deletion contracts/test/mocks/GatewayUpgradeMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// SPDX-FileCopyrightText: 2023 Snowfork <[email protected]>
pragma solidity 0.8.20;

import {Channel, InboundMessage, OperatingMode, ParaID, Config, Command} from "../../src/Types.sol";
import {Channel, InboundMessage, OperatingMode, ParaID, Config, Command, AssetFees} from "../../src/Types.sol";
import {IGateway} from "../../src/interfaces/IGateway.sol";
import {IInitializable} from "../../src/interfaces/IInitializable.sol";
import {Verification} from "../../src/Verification.sol";
Expand Down Expand Up @@ -32,6 +32,10 @@ contract GatewayUpgradeMock is IGateway, IInitializable {
return address(0);
}

function assetFees() external pure returns (AssetFees memory) {
vgeddes marked this conversation as resolved.
Show resolved Hide resolved
return AssetFees({register: 1, send: 1});
}

function implementation() external pure returns (address) {
return address(0);
}
Expand Down
32 changes: 31 additions & 1 deletion parachain/pallets/control/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,12 @@ use frame_support::{
};
use frame_system::pallet_prelude::*;
use snowbridge_core::{
outbound::{Command, Initializer, Message, OperatingMode, ParaId, SendError, SendMessage},
outbound::{
Command, Initializer, Message, OperatingMode, ParaId, SendError, SendMessage, TokenFees,
},
sibling_sovereign_account, AgentId,
};
use sp_runtime::SaturatedConversion;

#[cfg(feature = "runtime-benchmarks")]
use frame_support::traits::OriginTrait;
Expand Down Expand Up @@ -176,6 +179,8 @@ pub mod pallet {
SetOperatingMode { mode: OperatingMode },
/// An TransferNativeFromAgent message was sent to the Gateway
TransferNativeFromAgent { agent_id: AgentId, recipient: H160, amount: u128 },
/// An UpdateFees message was sent to the Gateway
UpdateFees { register: u128, send: u128 },
yrong marked this conversation as resolved.
Show resolved Hide resolved
}

#[pallet::error]
Expand Down Expand Up @@ -424,6 +429,31 @@ pub mod pallet {

Self::do_transfer_native_from_agent(agent_id, para_id, recipient, amount, pays_fee)
}

/// Sends a message to the Gateway contract to update fees
///
/// Privileged. Can only be called by root.
///
/// Fee required: No
///
/// - `origin`: Must be root
/// - `location`: Location used to resolve the agent
/// - `recipient`: Recipient of funds
/// - `amount`: Amount to transfer
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Documentation needs to be updated.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#[pallet::call_index(8)]
#[pallet::weight(T::WeightInfo::update_fees())]
pub fn update_fees(origin: OriginFor<T>, fees: TokenFees<BalanceOf<T>>) -> DispatchResult {
vgeddes marked this conversation as resolved.
Show resolved Hide resolved
ensure_root(origin)?;

let (register, send) =
(fees.register.saturated_into::<u128>(), fees.send.saturated_into::<u128>());

let command = Command::SetTokenFee { register, send };
Self::send(T::OwnParaId::get(), command, PaysFee::<T>::No)?;

Self::deposit_event(Event::<T>::UpdateFees { register, send });
Ok(())
}
}

impl<T: Config> Pallet<T> {
Expand Down
21 changes: 21 additions & 0 deletions parachain/pallets/control/src/weights.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ pub trait WeightInfo {
fn set_operating_mode() -> Weight;
fn transfer_native_from_agent() -> Weight;
fn force_transfer_native_from_agent() -> Weight;
fn update_fees() -> Weight;
}

// For backwards compatibility and tests.
Expand Down Expand Up @@ -204,4 +205,24 @@ impl WeightInfo for () {
.saturating_add(RocksDbWeight::get().reads(5_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 update_fees() -> 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))
}
}
22 changes: 22 additions & 0 deletions parachain/primitives/core/src/outbound.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,13 @@ mod v1 {
/// The amount to transfer
amount: u128,
},
/// Set token fees of the Gateway contract
SetTokenFee {
yrong marked this conversation as resolved.
Show resolved Hide resolved
/// The fee for register token
register: u128,
/// The fee for send token to para chain
send: u128,
},
}

impl Command {
Expand All @@ -124,6 +131,7 @@ mod v1 {
Command::UpdateChannel { .. } => 4,
Command::SetOperatingMode { .. } => 5,
Command::TransferNativeFromAgent { .. } => 6,
Command::SetTokenFee { .. } => 7,
}
}

Expand Down Expand Up @@ -170,6 +178,10 @@ mod v1 {
Token::Address(*recipient),
Token::Uint(U256::from(*amount)),
])]),
Command::SetTokenFee { register, send } => ethabi::encode(&[Token::Tuple(vec![
Token::Uint(U256::from(*register)),
Token::Uint(U256::from(*send)),
])]),
}
}
}
Expand Down Expand Up @@ -335,6 +347,7 @@ impl GasMeter for ConstantGasMeter {
// the the initializer is called.
50_000 + initializer_max_gas
},
Command::SetTokenFee { .. } => 60_000,
}
}
}
Expand Down Expand Up @@ -367,3 +380,12 @@ pub enum AggregateMessageOrigin {
}

pub const ETHER_DECIMALS: u8 = 18;

#[derive(Copy, Clone, Encode, Decode, PartialEq, Eq, RuntimeDebug, TypeInfo)]
pub struct TokenFees<Balance>
vgeddes marked this conversation as resolved.
Show resolved Hide resolved
where
Balance: BaseArithmetic + Unsigned + Copy,
{
pub register: Balance,
pub send: Balance,
}
Loading
Loading