Skip to content

Commit

Permalink
Pull SendError top level & Add Register token to System pallet
Browse files Browse the repository at this point in the history
  • Loading branch information
yrong committed Nov 4, 2024
1 parent f9024d6 commit 74d23af
Show file tree
Hide file tree
Showing 14 changed files with 165 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ use frame_support::{
traits::{EnqueueMessage, Get},
};
use snowbridge_core::outbound::{
v2::{primary_governance_origin, Message, SendError, SendMessage},
SendMessageFeeProvider,
v2::{primary_governance_origin, Message, SendMessage},
SendError, SendMessageFeeProvider,
};
use sp_core::H256;
use sp_runtime::BoundedVec;
Expand Down
5 changes: 4 additions & 1 deletion bridges/snowbridge/pallets/outbound-queue-v2/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ use frame_support::{

use codec::Encode;
use snowbridge_core::{
outbound::v2::{primary_governance_origin, Command, SendError, SendMessage},
outbound::{
v2::{primary_governance_origin, Command, SendMessage},
SendError,
},
ChannelId, ParaId,
};
use sp_core::H256;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ use frame_support::{
use frame_system::unique;
use snowbridge_core::{
outbound::{
v1::{Fee, Message, QueuedMessage, SendError, SendMessage, VersionedQueuedMessage},
SendMessageFeeProvider,
v1::{Fee, Message, QueuedMessage, SendMessage, VersionedQueuedMessage},
SendError, SendMessageFeeProvider,
},
ChannelId, PRIMARY_GOVERNANCE_CHANNEL,
};
Expand Down
5 changes: 4 additions & 1 deletion bridges/snowbridge/pallets/outbound-queue/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ use frame_support::{

use codec::Encode;
use snowbridge_core::{
outbound::v1::{Command, SendError, SendMessage},
outbound::{
v1::{Command, SendMessage},
SendError,
},
ParaId, PricingParameters, Rewards,
};
use sp_arithmetic::FixedU128;
Expand Down
103 changes: 100 additions & 3 deletions bridges/snowbridge/pallets/system/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,9 @@ use frame_system::pallet_prelude::*;
use snowbridge_core::{
meth,
outbound::{
v1::{Command, Initializer, Message, SendError, SendMessage},
OperatingMode,
v1::{Command, Initializer, Message, SendMessage},
v2::{Command as CommandV2, Message as MessageV2, SendMessage as SendMessageV2},
OperatingMode, SendError,
},
sibling_sovereign_account, AgentId, AssetMetadata, Channel, ChannelId, ParaId,
PricingParameters as PricingParametersRecord, TokenId, TokenIdOf, PRIMARY_GOVERNANCE_CHANNEL,
Expand Down Expand Up @@ -140,7 +141,7 @@ where
#[frame_support::pallet]
pub mod pallet {
use frame_support::dispatch::PostDispatchInfo;
use snowbridge_core::StaticLookup;
use snowbridge_core::{outbound::v2::second_governance_origin, StaticLookup};
use sp_core::U256;

use super::*;
Expand All @@ -155,6 +156,8 @@ pub mod pallet {
/// Send messages to Ethereum
type OutboundQueue: SendMessage<Balance = BalanceOf<Self>>;

type OutboundQueueV2: SendMessageV2<Balance = BalanceOf<Self>>;

/// Origin check for XCM locations that can create agents
type SiblingOrigin: EnsureOrigin<Self::RuntimeOrigin, Success = Location>;

Expand Down Expand Up @@ -638,6 +641,34 @@ pub mod pallet {
pays_fee: Pays::No,
})
}

/// Registers a Polkadot-native token as a wrapped ERC20 token on Ethereum.
/// Privileged. Can only be called by root.
///
/// Fee required: No
///
/// - `origin`: Must be root
/// - `location`: Location of the asset (relative to this chain)
/// - `metadata`: Metadata to include in the instantiated ERC20 contract on Ethereum
#[pallet::call_index(11)]
#[pallet::weight(T::WeightInfo::register_token())]
pub fn register_token_v2(
origin: OriginFor<T>,
location: Box<VersionedLocation>,
metadata: AssetMetadata,
) -> DispatchResultWithPostInfo {
ensure_root(origin)?;

let location: Location =
(*location).try_into().map_err(|_| Error::<T>::UnsupportedLocationVersion)?;

Self::do_register_token_v2(&location, metadata, PaysFee::<T>::No)?;

Ok(PostDispatchInfo {
actual_weight: Some(T::WeightInfo::register_token()),
pays_fee: Pays::No,
})
}
}

impl<T: Config> Pallet<T> {
Expand Down Expand Up @@ -763,6 +794,72 @@ pub mod pallet {

Ok(())
}

pub(crate) fn do_register_token_v2(
location: &Location,
metadata: AssetMetadata,
pays_fee: PaysFee<T>,
) -> Result<(), DispatchError> {
let ethereum_location = T::EthereumLocation::get();
// reanchor to Ethereum context
let location = location
.clone()
.reanchored(&ethereum_location, &T::UniversalLocation::get())
.map_err(|_| Error::<T>::LocationConversionFailed)?;

let token_id = TokenIdOf::convert_location(&location)
.ok_or(Error::<T>::LocationConversionFailed)?;

if !ForeignToNativeId::<T>::contains_key(token_id) {
NativeToForeignId::<T>::insert(location.clone(), token_id);
ForeignToNativeId::<T>::insert(token_id, location.clone());
}

let command = CommandV2::RegisterForeignToken {
token_id,
name: metadata.name.into_inner(),
symbol: metadata.symbol.into_inner(),
decimals: metadata.decimals,
};
Self::send_v2(second_governance_origin(), command, pays_fee)?;

Self::deposit_event(Event::<T>::RegisterToken {
location: location.clone().into(),
foreign_token_id: token_id,
});

Ok(())
}

/// Send `command` to the Gateway on the Channel identified by `channel_id`
fn send_v2(origin: H256, command: CommandV2, pays_fee: PaysFee<T>) -> DispatchResult {
let message = MessageV2 {
origin,
id: Default::default(),
fee: Default::default(),
commands: BoundedVec::try_from(vec![command]).unwrap(),
};

let (ticket, fee) =
T::OutboundQueueV2::validate(&message).map_err(|err| Error::<T>::Send(err))?;

let payment = match pays_fee {
PaysFee::Yes(account) | PaysFee::Partial(account) => Some((account, fee.total())),
PaysFee::No => None,
};

if let Some((payer, fee)) = payment {
T::Token::transfer(
&payer,
&T::TreasuryAccount::get(),
fee,
Preservation::Preserve,
)?;
}

T::OutboundQueueV2::deliver(ticket).map_err(|err| Error::<T>::Send(err))?;
Ok(())
}
}

impl<T: Config> StaticLookup for Pallet<T> {
Expand Down
12 changes: 10 additions & 2 deletions bridges/snowbridge/pallets/system/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,15 @@ use sp_core::H256;
use xcm_executor::traits::ConvertLocation;

use snowbridge_core::{
gwei, meth, outbound::v1::ConstantGasMeter, sibling_sovereign_account, AgentId,
AllowSiblingsOnly, ParaId, PricingParameters, Rewards,
gwei, meth,
outbound::{
v1::ConstantGasMeter,
v2::{
DefaultOutboundQueue, Fee as FeeV2, Message as MessageV2, SendMessage as SendMessageV2,
},
SendError, SendMessageFeeProvider,
},
sibling_sovereign_account, AgentId, AllowSiblingsOnly, ParaId, PricingParameters, Rewards,
};
use sp_runtime::{
traits::{AccountIdConversion, BlakeTwo256, IdentityLookup, Keccak256},
Expand Down Expand Up @@ -213,6 +220,7 @@ impl crate::Config for Test {
type EthereumLocation = EthereumDestination;
#[cfg(feature = "runtime-benchmarks")]
type Helper = ();
type OutboundQueueV2 = DefaultOutboundQueue;
}

// Build genesis storage according to the mock runtime.
Expand Down
12 changes: 12 additions & 0 deletions bridges/snowbridge/primitives/core/src/outbound/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
//!
//! Common traits and types
use codec::{Decode, Encode};
use frame_support::PalletError;
use scale_info::TypeInfo;
use sp_arithmetic::traits::{BaseArithmetic, Unsigned};
use sp_core::RuntimeDebug;
Expand All @@ -30,6 +31,17 @@ pub trait SendMessageFeeProvider {
fn local_fee() -> Self::Balance;
}

/// Reasons why sending to Ethereum could not be initiated
#[derive(Copy, Clone, Encode, Decode, PartialEq, Eq, RuntimeDebug, PalletError, TypeInfo)]
pub enum SendError {
/// Message is too large to be safely executed on Ethereum
MessageTooLarge,
/// The bridge has been halted for maintenance
Halted,
/// Invalid Channel
InvalidChannel,
}

#[derive(Copy, Clone, Encode, Decode, Eq, PartialEq, Debug, TypeInfo)]
pub enum DryRunError {
ConvertFailed,
Expand Down
14 changes: 1 addition & 13 deletions bridges/snowbridge/primitives/core/src/outbound/v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@
//! # Outbound V1 primitives
use crate::{
outbound::{OperatingMode, SendMessageFeeProvider},
outbound::{OperatingMode, SendError, SendMessageFeeProvider},
pricing::UD60x18,
ChannelId,
};
use codec::{Decode, Encode};
use ethabi::Token;
use frame_support::PalletError;
use scale_info::TypeInfo;
use sp_arithmetic::traits::{BaseArithmetic, Unsigned};
use sp_core::{RuntimeDebug, H160, H256, U256};
Expand Down Expand Up @@ -365,17 +364,6 @@ pub trait Ticket: Encode + Decode + Clone {
fn message_id(&self) -> H256;
}

/// Reasons why sending to Ethereum could not be initiated
#[derive(Copy, Clone, Encode, Decode, PartialEq, Eq, RuntimeDebug, PalletError, TypeInfo)]
pub enum SendError {
/// Message is too large to be safely executed on Ethereum
MessageTooLarge,
/// The bridge has been halted for maintenance
Halted,
/// Invalid Channel
InvalidChannel,
}

pub trait GasMeter {
/// All the gas used for submitting a message to Ethereum, minus the cost of dispatching
/// the command within the message
Expand Down
32 changes: 21 additions & 11 deletions bridges/snowbridge/primitives/core/src/outbound/v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
// SPDX-FileCopyrightText: 2023 Snowfork <[email protected]>
//! # Outbound V2 primitives
use crate::outbound::{OperatingMode, SendMessageFeeProvider};
use crate::outbound::{OperatingMode, SendError, SendMessageFeeProvider};
use alloy_sol_types::sol;
use codec::{Decode, Encode};
use frame_support::{pallet_prelude::ConstU32, BoundedVec, PalletError};
use frame_support::{pallet_prelude::ConstU32, BoundedVec};
use hex_literal::hex;
use scale_info::TypeInfo;
use sp_arithmetic::traits::{BaseArithmetic, Unsigned};
Expand Down Expand Up @@ -266,15 +266,25 @@ pub trait SendMessage: SendMessageFeeProvider {
fn deliver(ticket: Self::Ticket) -> Result<H256, SendError>;
}

/// Reasons why sending to Ethereum could not be initiated
#[derive(Copy, Clone, Encode, Decode, PartialEq, Eq, RuntimeDebug, PalletError, TypeInfo)]
pub enum SendError {
/// Message is too large to be safely executed on Ethereum
MessageTooLarge,
/// The bridge has been halted for maintenance
Halted,
/// Invalid Channel
InvalidChannel,
pub struct DefaultOutboundQueue;
impl SendMessage for DefaultOutboundQueue {
type Ticket = ();

fn validate(_: &Message) -> Result<(Self::Ticket, Fee<Self::Balance>), SendError> {
Ok(((), Fee { local: Default::default() }))
}

fn deliver(_: Self::Ticket) -> Result<H256, SendError> {
Ok(H256::zero())
}
}

impl SendMessageFeeProvider for DefaultOutboundQueue {
type Balance = u128;

fn local_fee() -> Self::Balance {
Default::default()
}
}

pub trait GasMeter {
Expand Down
5 changes: 1 addition & 4 deletions bridges/snowbridge/primitives/router/src/outbound/v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -410,10 +410,7 @@ mod tests {
use frame_support::parameter_types;
use hex_literal::hex;
use snowbridge_core::{
outbound::{
v1::{Fee, SendError},
SendMessageFeeProvider,
},
outbound::{v1::Fee, SendError, SendMessageFeeProvider},
AgentIdOf,
};
use sp_std::default::Default;
Expand Down
5 changes: 1 addition & 4 deletions bridges/snowbridge/primitives/router/src/outbound/v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -482,10 +482,7 @@ mod tests {
use frame_support::parameter_types;
use hex_literal::hex;
use snowbridge_core::{
outbound::{
v2::{Fee, SendError},
SendMessageFeeProvider,
},
outbound::{v2::Fee, SendError, SendMessageFeeProvider},
AgentIdOf,
};
use sp_std::default::Default;
Expand Down
4 changes: 2 additions & 2 deletions bridges/snowbridge/runtime/runtime-common/src/tests.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::XcmExportFeeToSibling;
use frame_support::{parameter_types, sp_runtime::testing::H256};
use snowbridge_core::outbound::{
v1::{Fee, Message, SendError, SendMessage},
SendMessageFeeProvider,
v1::{Fee, Message, SendMessage},
SendError, SendMessageFeeProvider,
};
use xcm::prelude::{
Asset, Assets, Here, Kusama, Location, NetworkId, Parachain, XcmContext, XcmError, XcmHash,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ use crate::xcm_config::RelayNetwork;
use benchmark_helpers::DoNothingRouter;
use frame_support::{parameter_types, weights::ConstantMultiplier};
use pallet_xcm::EnsureXcm;
use snowbridge_core::outbound::v2::DefaultOutboundQueue;
use sp_runtime::{
traits::{ConstU32, ConstU8, Keccak256},
FixedU128,
Expand Down Expand Up @@ -191,6 +192,7 @@ impl snowbridge_pallet_system::Config for Runtime {
type InboundDeliveryCost = EthereumInboundQueue;
type UniversalLocation = UniversalLocation;
type EthereumLocation = EthereumLocation;
type OutboundQueueV2 = DefaultOutboundQueue;
}

#[cfg(feature = "runtime-benchmarks")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ use crate::XcmRouter;
use crate::{
xcm_config,
xcm_config::{TreasuryAccount, UniversalLocation},
Balances, EthereumInboundQueue, EthereumOutboundQueue, EthereumSystem, MessageQueue, Runtime,
RuntimeEvent, TransactionByteFee,
Balances, EthereumInboundQueue, EthereumOutboundQueue, EthereumOutboundQueueV2, EthereumSystem,
MessageQueue, Runtime, RuntimeEvent, TransactionByteFee,
};
use parachains_common::{AccountId, Balance};
use snowbridge_beacon_primitives::{Fork, ForkVersions};
Expand Down Expand Up @@ -248,6 +248,7 @@ impl snowbridge_pallet_system::Config for Runtime {
type InboundDeliveryCost = EthereumInboundQueue;
type UniversalLocation = UniversalLocation;
type EthereumLocation = EthereumLocation;
type OutboundQueueV2 = EthereumOutboundQueueV2;
}

#[cfg(feature = "runtime-benchmarks")]
Expand Down

0 comments on commit 74d23af

Please sign in to comment.