snowbridge_outbound_queue_primitives/v2/
message.rsuse codec::{Decode, DecodeWithMemTracking, Encode};
use frame_support::{pallet_prelude::ConstU32, BoundedVec};
use scale_info::TypeInfo;
use sp_core::{RuntimeDebug, H160, H256};
use sp_std::vec::Vec;
use crate::{OperatingMode, SendError};
use abi::{
CallContractParams, MintForeignTokenParams, RegisterForeignTokenParams, SetOperatingModeParams,
UnlockNativeTokenParams, UpgradeParams,
};
use alloy_core::{
primitives::{Address, Bytes, FixedBytes, U256},
sol_types::SolValue,
};
pub mod abi {
use alloy_core::sol;
sol! {
struct OutboundMessageWrapper {
bytes32 origin;
uint64 nonce;
bytes32 topic;
CommandWrapper[] commands;
}
struct CommandWrapper {
uint8 kind;
uint64 gas;
bytes payload;
}
struct UpgradeParams {
address implAddress;
bytes32 implCodeHash;
bytes initParams;
}
struct SetOperatingModeParams {
uint8 mode;
}
struct UnlockNativeTokenParams {
address token;
address recipient;
uint128 amount;
}
struct RegisterForeignTokenParams {
bytes32 foreignTokenID;
bytes name;
bytes symbol;
uint8 decimals;
}
struct MintForeignTokenParams {
bytes32 foreignTokenID;
address recipient;
uint128 amount;
}
struct CallContractParams {
address target;
bytes data;
uint256 value;
}
}
}
#[derive(Encode, Decode, TypeInfo, PartialEq, Clone, RuntimeDebug)]
pub struct OutboundCommandWrapper {
pub kind: u8,
pub gas: u64,
pub payload: Vec<u8>,
}
#[derive(Encode, Decode, TypeInfo, PartialEq, Clone, RuntimeDebug)]
pub struct OutboundMessage {
pub origin: H256,
pub nonce: u64,
pub topic: H256,
pub commands: BoundedVec<OutboundCommandWrapper, ConstU32<MAX_COMMANDS>>,
}
pub const MAX_COMMANDS: u32 = 8;
#[derive(Encode, Decode, DecodeWithMemTracking, TypeInfo, PartialEq, Clone, RuntimeDebug)]
pub struct Message {
pub origin: H256,
pub id: H256,
pub fee: u128,
pub commands: BoundedVec<Command, ConstU32<MAX_COMMANDS>>,
}
#[derive(Clone, Encode, Decode, DecodeWithMemTracking, PartialEq, RuntimeDebug, TypeInfo)]
pub enum Command {
Upgrade {
impl_address: H160,
impl_code_hash: H256,
initializer: Initializer,
},
SetOperatingMode {
mode: OperatingMode,
},
UnlockNativeToken {
token: H160,
recipient: H160,
amount: u128,
},
RegisterForeignToken {
token_id: H256,
name: Vec<u8>,
symbol: Vec<u8>,
decimals: u8,
},
MintForeignToken {
token_id: H256,
recipient: H160,
amount: u128,
},
CallContract {
target: H160,
calldata: Vec<u8>,
gas: u64,
value: u128,
},
}
impl Command {
pub fn index(&self) -> u8 {
match self {
Command::Upgrade { .. } => 0,
Command::SetOperatingMode { .. } => 1,
Command::UnlockNativeToken { .. } => 2,
Command::RegisterForeignToken { .. } => 3,
Command::MintForeignToken { .. } => 4,
Command::CallContract { .. } => 5,
}
}
pub fn abi_encode(&self) -> Vec<u8> {
match self {
Command::Upgrade { impl_address, impl_code_hash, initializer, .. } => UpgradeParams {
implAddress: Address::from(impl_address.as_fixed_bytes()),
implCodeHash: FixedBytes::from(impl_code_hash.as_fixed_bytes()),
initParams: Bytes::from(initializer.params.clone()),
}
.abi_encode(),
Command::SetOperatingMode { mode } =>
SetOperatingModeParams { mode: (*mode) as u8 }.abi_encode(),
Command::UnlockNativeToken { token, recipient, amount, .. } =>
UnlockNativeTokenParams {
token: Address::from(token.as_fixed_bytes()),
recipient: Address::from(recipient.as_fixed_bytes()),
amount: *amount,
}
.abi_encode(),
Command::RegisterForeignToken { token_id, name, symbol, decimals } =>
RegisterForeignTokenParams {
foreignTokenID: FixedBytes::from(token_id.as_fixed_bytes()),
name: Bytes::from(name.to_vec()),
symbol: Bytes::from(symbol.to_vec()),
decimals: *decimals,
}
.abi_encode(),
Command::MintForeignToken { token_id, recipient, amount } => MintForeignTokenParams {
foreignTokenID: FixedBytes::from(token_id.as_fixed_bytes()),
recipient: Address::from(recipient.as_fixed_bytes()),
amount: *amount,
}
.abi_encode(),
Command::CallContract { target, calldata: data, value, .. } => CallContractParams {
target: Address::from(target.as_fixed_bytes()),
data: Bytes::from(data.to_vec()),
value: U256::try_from(*value).unwrap(),
}
.abi_encode(),
}
}
}
#[derive(Clone, Encode, Decode, DecodeWithMemTracking, PartialEq, RuntimeDebug, TypeInfo)]
pub struct Initializer {
pub params: Vec<u8>,
pub maximum_required_gas: u64,
}
pub trait SendMessage {
type Ticket: Clone + Encode + Decode;
fn validate(message: &Message) -> Result<Self::Ticket, SendError>;
fn deliver(ticket: Self::Ticket) -> Result<H256, SendError>;
}
pub trait GasMeter {
fn maximum_dispatch_gas_used_at_most(command: &Command) -> u64;
}
pub struct ConstantGasMeter;
impl GasMeter for ConstantGasMeter {
fn maximum_dispatch_gas_used_at_most(command: &Command) -> u64 {
match command {
Command::SetOperatingMode { .. } => 40_000,
Command::Upgrade { initializer, .. } => {
50_000 + initializer.maximum_required_gas
},
Command::UnlockNativeToken { .. } => 100_000,
Command::RegisterForeignToken { .. } => 1_200_000,
Command::MintForeignToken { .. } => 100_000,
Command::CallContract { gas: gas_limit, .. } => *gas_limit,
}
}
}
impl GasMeter for () {
fn maximum_dispatch_gas_used_at_most(_: &Command) -> u64 {
1
}
}