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 6 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
2 changes: 2 additions & 0 deletions parachain/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion parachain/pallets/control/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ frame-benchmarking = { git = "https://github.com/paritytech/substrate.git", bran
frame-support = { git = "https://github.com/paritytech/substrate.git", branch = "master", default-features = false }
frame-system = { git = "https://github.com/paritytech/substrate.git", branch = "master", default-features = false }
snowbridge-core = { path = "../../primitives/core", default-features = false }
snowbridge-router-primitives = { path = "../../primitives/router", default-features = false }

sp-core = { git = "https://github.com/paritytech/substrate.git", branch = "master", default-features = false }
sp-std = { git = "https://github.com/paritytech/substrate.git", branch = "master", default-features = false }
Expand All @@ -36,6 +37,7 @@ ethabi = { git = "https://github.com/Snowfork/ethabi-decode.git", package = "eth
[dev-dependencies]
hex = "0.4.1"
hex-literal = { version = "0.4.1" }
pallet-balances = { git = "https://github.com/paritytech/substrate.git", branch = "master" }

[features]
default = ["std"]
Expand All @@ -52,7 +54,8 @@ std = [
"xcm/std",
"xcm-builder/std",
"xcm-executor/std",
"ethabi/std"
"ethabi/std",
"snowbridge-router-primitives/std",
]
runtime-benchmarks = [
"frame-benchmarking/runtime-benchmarks",
Expand Down
136 changes: 114 additions & 22 deletions parachain/pallets/control/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ mod benchmarking;
pub mod weights;
pub use weights::*;

use frame_support::traits::fungible::{Inspect, Mutate};
use snowbridge_core::{
outbound::{Command, Message, OperatingMode, OutboundQueue as OutboundQueueTrait, ParaId},
AgentId,
Expand All @@ -31,17 +32,27 @@ pub use pallet::*;

pub const LOG_TARGET: &str = "snowbridge-control";

type BalanceOf<T> =
<<T as pallet::Config>::Token as Inspect<<T as frame_system::Config>::AccountId>>::Balance;

#[frame_support::pallet]
pub mod pallet {
use super::*;
use frame_support::{log, pallet_prelude::*, traits::EnsureOrigin};
use frame_support::{
log,
pallet_prelude::*,
sp_runtime::{traits::AccountIdConversion, AccountId32},
traits::{tokens::Preservation, EnsureOrigin},
PalletId,
};
use frame_system::pallet_prelude::*;
use snowbridge_core::outbound::ControlOperation;

#[pallet::pallet]
pub struct Pallet<T>(_);

#[pallet::config]
pub trait Config: frame_system::Config {
pub trait Config: frame_system::Config<AccountId = AccountId32> {
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;

/// General-purpose hasher
Expand All @@ -63,26 +74,41 @@ pub mod pallet {
type ChannelOrigin: EnsureOrigin<Self::RuntimeOrigin, Success = MultiLocation>;

/// Converts MultiLocation to H256 in a way that is stable across multiple versions of XCM
type AgentHashedDescription: ConvertLocation<H256>;
type AgentIdOf: ConvertLocation<H256>;
vgeddes marked this conversation as resolved.
Show resolved Hide resolved

type SovereignAccountOf: ConvertLocation<Self::AccountId>;

/// The universal location
type UniversalLocation: Get<InteriorMultiLocation>;

/// Location of the relay chain
type RelayLocation: Get<MultiLocation>;

/// Token reserved for control operations
type Token: Mutate<Self::AccountId>;

type WeightInfo: WeightInfo;
}

#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
/// An Upgrade message was sent to the Gateway
Upgrade { impl_address: H160, impl_code_hash: H256, params_hash: Option<H256> },
Upgrade {
impl_address: H160,
impl_code_hash: H256,
params_hash: Option<H256>,
},
/// An CreateAgent message was sent to the Gateway
CreateAgent { location: Box<MultiLocation>, agent_id: AgentId },
CreateAgent {
location: Box<MultiLocation>,
agent_id: AgentId,
},
/// An CreateChannel message was sent to the Gateway
CreateChannel { para_id: ParaId, agent_id: AgentId },
CreateChannel {
para_id: ParaId,
agent_id: AgentId,
},
/// An UpdateChannel message was sent to the Gateway
UpdateChannel {
para_id: ParaId,
Expand All @@ -92,9 +118,19 @@ pub mod pallet {
reward: 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,
},
FeeUpdated {
operation: ControlOperation,
fee: BalanceOf<T>,
},
}

#[pallet::error]
Expand All @@ -108,6 +144,7 @@ pub mod pallet {
AgentNotExist,
ChannelAlreadyCreated,
ChannelNotExist,
LocationToAgentAccountConversionFailed,
}

#[pallet::storage]
Expand All @@ -116,6 +153,10 @@ pub mod pallet {
#[pallet::storage]
pub type Channels<T: Config> = StorageMap<_, Twox64Concat, ParaId, (), OptionQuery>;

#[pallet::storage]
pub type ControlOperationFee<T: Config> =
StorageMap<_, Twox64Concat, ControlOperation, BalanceOf<T>, ValueQuery>;

#[pallet::call]
impl<T: Config> Pallet<T> {
/// Sends a message to the Gateway contract to upgrade itself.
Expand Down Expand Up @@ -170,6 +211,11 @@ pub mod pallet {
location
);

Self::reserve_deposit(
Self::agent_account_id(&location)?,
ControlOperationFee::<T>::get(ControlOperation::CreateAgent),
)?;

// Record the agent id or fail if it has already been created
ensure!(!Agents::<T>::contains_key(agent_id), Error::<T>::AgentAlreadyCreated);

Expand Down Expand Up @@ -197,14 +243,17 @@ pub mod pallet {
pub fn create_channel(origin: OriginFor<T>) -> DispatchResult {
let location: MultiLocation = T::ChannelOrigin::ensure_origin(origin)?;

let (agent_id, some_para_id, _) = Self::convert_location(location)?;
let (agent_id, para_id, location) = Self::convert_location(location)?;

ensure!(Agents::<T>::contains_key(agent_id), Error::<T>::AgentNotExist);

let para_id = some_para_id.ok_or(Error::<T>::LocationToParaIdConversionFailed)?;

ensure!(!Channels::<T>::contains_key(para_id), Error::<T>::ChannelAlreadyCreated);

Self::reserve_deposit(
Self::agent_account_id(&location)?,
ControlOperationFee::<T>::get(ControlOperation::CreateChannel),
)?;

Channels::<T>::insert(para_id, ());

let message = Message {
Expand All @@ -231,14 +280,17 @@ pub mod pallet {
) -> DispatchResult {
let location: MultiLocation = T::ChannelOrigin::ensure_origin(origin)?;

let (agent_id, some_para_id, _) = Self::convert_location(location)?;
let (agent_id, para_id, location) = Self::convert_location(location)?;

ensure!(Agents::<T>::contains_key(agent_id), Error::<T>::AgentNotExist);

let para_id = some_para_id.ok_or(Error::<T>::LocationToParaIdConversionFailed)?;

ensure!(Channels::<T>::contains_key(para_id), Error::<T>::ChannelNotExist);

Self::reserve_deposit(
Self::agent_account_id(&location)?,
ControlOperationFee::<T>::get(ControlOperation::UpdateChannel),
)?;

let message = Message {
origin: T::OwnParaId::get(),
command: Command::UpdateChannel { para_id, mode, fee, reward },
Expand Down Expand Up @@ -281,10 +333,15 @@ pub mod pallet {
) -> DispatchResult {
let location: MultiLocation = T::AgentOrigin::ensure_origin(origin)?;

let (agent_id, _, _) = Self::convert_location(location)?;
let (agent_id, _, location) = Self::convert_location(location)?;

ensure!(Agents::<T>::contains_key(agent_id), Error::<T>::AgentNotExist);

Self::reserve_deposit(
Self::agent_account_id(&location)?,
ControlOperationFee::<T>::get(ControlOperation::TransferNativeFromAgent),
)?;

let message = Message {
origin: T::OwnParaId::get(),
command: Command::TransferNativeFromAgent { agent_id, recipient, amount },
Expand All @@ -299,6 +356,27 @@ pub mod pallet {

Ok(())
}

/// - `update`: (ControlOperation, Fee).
#[pallet::call_index(6)]
#[pallet::weight(T::WeightInfo::update_operation_fee())]
pub fn update_operation_fee(
yrong marked this conversation as resolved.
Show resolved Hide resolved
yrong marked this conversation as resolved.
Show resolved Hide resolved
origin: OriginFor<T>,
operation: ControlOperation,
update_fee: BalanceOf<T>,
) -> DispatchResult {
ensure_root(origin)?;

ControlOperationFee::<T>::mutate(&operation, |fee| {
*fee = update_fee;
Self::deposit_event(Event::<T>::FeeUpdated {
operation: operation.clone(),
fee: update_fee,
});
});

Ok(())
}
}

impl<T: Config> Pallet<T> {
Expand All @@ -311,25 +389,39 @@ pub mod pallet {

pub fn convert_location(
yrong marked this conversation as resolved.
Show resolved Hide resolved
mut location: MultiLocation,
) -> Result<(H256, Option<ParaId>, MultiLocation), DispatchError> {
) -> Result<(H256, ParaId, MultiLocation), DispatchError> {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Lets rather return a struct to make the code self-documenting:

Suggested change
) -> Result<(H256, ParaId, MultiLocation), DispatchError> {
) -> Result<OriginInfo, DispatchError> {
struct OriginInfo {
    agent_id: H256,
    para_id: ParaId,
    location: MultiLocation,
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

// Normalize all locations relative to the relay chain.
let relay_location = T::RelayLocation::get();
location
.reanchor(&relay_location, T::UniversalLocation::get())
.map_err(|_| Error::<T>::LocationReanchorFailed)?;

// Only allow Parachain as origin location
let para_id = match location {
MultiLocation { parents: 0, interior: X1(Parachain(index)) } =>
Some((index).into()),
let para_id = match location.interior.first() {
Some(Parachain(index)) => Some((*index).into()),
_ => None,
};
}
.ok_or(Error::<T>::LocationToParaIdConversionFailed)?;
alistair-singh marked this conversation as resolved.
Show resolved Hide resolved

// Hash the location to produce an agent id
let agent_id = T::AgentHashedDescription::convert_location(&location)
let agent_id = T::AgentIdOf::convert_location(&location)
.ok_or(Error::<T>::LocationToAgentIdConversionFailed)?;

Ok((agent_id, para_id, location))
}

pub fn account_id() -> T::AccountId {
PalletId(*b"snow/ctl").into_account_truncating()
yrong marked this conversation as resolved.
Show resolved Hide resolved
}

pub fn reserve_deposit(payer: T::AccountId, amount: BalanceOf<T>) -> DispatchResult {
T::Token::transfer(&payer, &Self::account_id(), amount, Preservation::Preserve)?;
Ok(())
}

pub fn agent_account_id(location: &MultiLocation) -> Result<T::AccountId, DispatchError> {
yrong marked this conversation as resolved.
Show resolved Hide resolved
let agent_account = T::SovereignAccountOf::convert_location(location)
.ok_or(Error::<T>::LocationToAgentAccountConversionFailed)?;
Ok(agent_account)
}
}
}
23 changes: 21 additions & 2 deletions parachain/pallets/control/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ frame_support::construct_runtime!(
UncheckedExtrinsic = UncheckedExtrinsic,
{
System: frame_system,
Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
EthereumControl: snowbridge_control,
}
);
Expand All @@ -54,7 +55,7 @@ impl frame_system::Config for Test {
type BlockHashCount = ConstU64<250>;
type Version = ();
type PalletInfo = PalletInfo;
type AccountData = ();
type AccountData = pallet_balances::AccountData<u64>;
type OnNewAccount = ();
type OnKilledAccount = ();
type SystemWeightInfo = ();
Expand All @@ -63,6 +64,22 @@ impl frame_system::Config for Test {
type MaxConsumers = frame_support::traits::ConstU32<16>;
}

impl pallet_balances::Config for Test {
type MaxLocks = ();
type MaxReserves = ();
type ReserveIdentifier = [u8; 8];
type Balance = u64;
type RuntimeEvent = RuntimeEvent;
type DustRemoval = ();
type ExistentialDeposit = ConstU64<1>;
type AccountStore = System;
type WeightInfo = ();
type FreezeIdentifier = ();
type MaxFreezes = ();
type RuntimeHoldReason = ();
type MaxHolds = ();
}

parameter_types! {
pub const OwnParaId: ParaId = ParaId::new(1013);
pub const MaxUpgradeDataSize: u32 = 1024;
Expand Down Expand Up @@ -195,7 +212,9 @@ impl snowbridge_control::Config for Test {
type ChannelOrigin = EnsureOriginFromTable;
type UniversalLocation = UniversalLocation;
type RelayLocation = RelayLocation;
type AgentHashedDescription = HashedDescription<H256, DescribeFamily<DescribeAllTerminal>>;
type AgentIdOf = HashedDescription<H256, DescribeFamily<DescribeAllTerminal>>;
type SovereignAccountOf = HashedDescription<AccountId, DescribeFamily<DescribeAllTerminal>>;
type Token = Balances;
type WeightInfo = ();
}

Expand Down
Loading