snowbridge_outbound_queue_primitives/v2/
message.rs1use codec::{Decode, DecodeWithMemTracking, Encode};
6use frame_support::{pallet_prelude::ConstU32, BoundedVec};
7use scale_info::TypeInfo;
8use sp_core::{RuntimeDebug, H160, H256};
9use sp_std::vec::Vec;
10
11use crate::{OperatingMode, SendError};
12use abi::{
13 CallContractParams, MintForeignTokenParams, RegisterForeignTokenParams, SetOperatingModeParams,
14 UnlockNativeTokenParams, UpgradeParams,
15};
16use alloy_core::{
17 primitives::{Address, Bytes, FixedBytes, U256},
18 sol_types::SolValue,
19};
20
21pub mod abi {
22 use alloy_core::sol;
23
24 sol! {
25 struct OutboundMessageWrapper {
26 bytes32 origin;
28 uint64 nonce;
30 bytes32 topic;
32 CommandWrapper[] commands;
34 }
35
36 struct CommandWrapper {
37 uint8 kind;
38 uint64 gas;
39 bytes payload;
40 }
41
42 struct UpgradeParams {
44 address implAddress;
46 bytes32 implCodeHash;
48 bytes initParams;
50 }
51
52 struct SetOperatingModeParams {
54 uint8 mode;
56 }
57
58 struct UnlockNativeTokenParams {
60 address token;
62 address recipient;
64 uint128 amount;
66 }
67
68 struct RegisterForeignTokenParams {
70 bytes32 foreignTokenID;
72 bytes name;
74 bytes symbol;
76 uint8 decimals;
78 }
79
80 struct MintForeignTokenParams {
82 bytes32 foreignTokenID;
84 address recipient;
86 uint128 amount;
88 }
89
90 struct CallContractParams {
92 address target;
94 bytes data;
96 uint256 value;
98 }
99 }
100}
101
102#[derive(Encode, Decode, TypeInfo, PartialEq, Clone, RuntimeDebug)]
103pub struct OutboundCommandWrapper {
104 pub kind: u8,
105 pub gas: u64,
106 pub payload: Vec<u8>,
107}
108
109#[derive(Encode, Decode, TypeInfo, PartialEq, Clone, RuntimeDebug)]
110pub struct OutboundMessage {
111 pub origin: H256,
113 pub nonce: u64,
115 pub topic: H256,
117 pub commands: BoundedVec<OutboundCommandWrapper, ConstU32<MAX_COMMANDS>>,
119}
120
121pub const MAX_COMMANDS: u32 = 8;
122
123#[derive(Encode, Decode, DecodeWithMemTracking, TypeInfo, PartialEq, Clone, RuntimeDebug)]
125pub struct Message {
126 pub origin: H256,
128 pub id: H256,
130 pub fee: u128,
132 pub commands: BoundedVec<Command, ConstU32<MAX_COMMANDS>>,
134}
135
136#[derive(Clone, Encode, Decode, DecodeWithMemTracking, PartialEq, RuntimeDebug, TypeInfo)]
138pub enum Command {
139 Upgrade {
141 impl_address: H160,
143 impl_code_hash: H256,
145 initializer: Initializer,
147 },
148 SetOperatingMode {
150 mode: OperatingMode,
152 },
153 UnlockNativeToken {
155 token: H160,
157 recipient: H160,
159 amount: u128,
161 },
162 RegisterForeignToken {
164 token_id: H256,
166 name: Vec<u8>,
168 symbol: Vec<u8>,
170 decimals: u8,
172 },
173 MintForeignToken {
175 token_id: H256,
177 recipient: H160,
179 amount: u128,
181 },
182 CallContract {
184 target: H160,
186 calldata: Vec<u8>,
188 gas: u64,
190 value: u128,
192 },
193}
194
195impl Command {
196 pub fn index(&self) -> u8 {
198 match self {
199 Command::Upgrade { .. } => 0,
200 Command::SetOperatingMode { .. } => 1,
201 Command::UnlockNativeToken { .. } => 2,
202 Command::RegisterForeignToken { .. } => 3,
203 Command::MintForeignToken { .. } => 4,
204 Command::CallContract { .. } => 5,
205 }
206 }
207
208 pub fn abi_encode(&self) -> Vec<u8> {
210 match self {
211 Command::Upgrade { impl_address, impl_code_hash, initializer, .. } => UpgradeParams {
212 implAddress: Address::from(impl_address.as_fixed_bytes()),
213 implCodeHash: FixedBytes::from(impl_code_hash.as_fixed_bytes()),
214 initParams: Bytes::from(initializer.params.clone()),
215 }
216 .abi_encode(),
217 Command::SetOperatingMode { mode } =>
218 SetOperatingModeParams { mode: (*mode) as u8 }.abi_encode(),
219 Command::UnlockNativeToken { token, recipient, amount, .. } =>
220 UnlockNativeTokenParams {
221 token: Address::from(token.as_fixed_bytes()),
222 recipient: Address::from(recipient.as_fixed_bytes()),
223 amount: *amount,
224 }
225 .abi_encode(),
226 Command::RegisterForeignToken { token_id, name, symbol, decimals } =>
227 RegisterForeignTokenParams {
228 foreignTokenID: FixedBytes::from(token_id.as_fixed_bytes()),
229 name: Bytes::from(name.to_vec()),
230 symbol: Bytes::from(symbol.to_vec()),
231 decimals: *decimals,
232 }
233 .abi_encode(),
234 Command::MintForeignToken { token_id, recipient, amount } => MintForeignTokenParams {
235 foreignTokenID: FixedBytes::from(token_id.as_fixed_bytes()),
236 recipient: Address::from(recipient.as_fixed_bytes()),
237 amount: *amount,
238 }
239 .abi_encode(),
240 Command::CallContract { target, calldata: data, value, .. } => CallContractParams {
241 target: Address::from(target.as_fixed_bytes()),
242 data: Bytes::from(data.to_vec()),
243 value: U256::try_from(*value).unwrap(),
244 }
245 .abi_encode(),
246 }
247 }
248}
249
250#[derive(Clone, Encode, Decode, DecodeWithMemTracking, PartialEq, RuntimeDebug, TypeInfo)]
253pub struct Initializer {
254 pub params: Vec<u8>,
256 pub maximum_required_gas: u64,
258}
259
260pub trait SendMessage {
261 type Ticket: Clone + Encode + Decode;
262
263 fn validate(message: &Message) -> Result<Self::Ticket, SendError>;
267
268 fn deliver(ticket: Self::Ticket) -> Result<H256, SendError>;
270}
271
272pub trait GasMeter {
273 fn maximum_dispatch_gas_used_at_most(command: &Command) -> u64;
276}
277
278pub struct ConstantGasMeter;
287
288impl GasMeter for ConstantGasMeter {
289 fn maximum_dispatch_gas_used_at_most(command: &Command) -> u64 {
290 match command {
291 Command::SetOperatingMode { .. } => 40_000,
292 Command::Upgrade { initializer, .. } => {
293 50_000 + initializer.maximum_required_gas
296 },
297 Command::UnlockNativeToken { .. } => 200_000,
298 Command::RegisterForeignToken { .. } => 1_200_000,
299 Command::MintForeignToken { .. } => 100_000,
300 Command::CallContract { gas: gas_limit, .. } => *gas_limit,
301 }
302 }
303}
304
305impl GasMeter for () {
306 fn maximum_dispatch_gas_used_at_most(_: &Command) -> u64 {
307 1
308 }
309}