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::{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, Debug)]
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, Debug)]
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, Debug)]
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, Debug, 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 },
220 Command::UnlockNativeToken { token, recipient, amount, .. } => {
221 UnlockNativeTokenParams {
222 token: Address::from(token.as_fixed_bytes()),
223 recipient: Address::from(recipient.as_fixed_bytes()),
224 amount: *amount,
225 }
226 .abi_encode()
227 },
228 Command::RegisterForeignToken { token_id, name, symbol, decimals } => {
229 RegisterForeignTokenParams {
230 foreignTokenID: FixedBytes::from(token_id.as_fixed_bytes()),
231 name: Bytes::from(name.to_vec()),
232 symbol: Bytes::from(symbol.to_vec()),
233 decimals: *decimals,
234 }
235 .abi_encode()
236 },
237 Command::MintForeignToken { token_id, recipient, amount } => MintForeignTokenParams {
238 foreignTokenID: FixedBytes::from(token_id.as_fixed_bytes()),
239 recipient: Address::from(recipient.as_fixed_bytes()),
240 amount: *amount,
241 }
242 .abi_encode(),
243 Command::CallContract { target, calldata: data, value, .. } => CallContractParams {
244 target: Address::from(target.as_fixed_bytes()),
245 data: Bytes::from(data.to_vec()),
246 value: U256::try_from(*value).unwrap(),
247 }
248 .abi_encode(),
249 }
250 }
251}
252
253#[derive(Clone, Encode, Decode, DecodeWithMemTracking, PartialEq, Debug, TypeInfo)]
256pub struct Initializer {
257 pub params: Vec<u8>,
259 pub maximum_required_gas: u64,
261}
262
263pub trait SendMessage {
264 type Ticket: Clone + Encode + Decode;
265
266 fn validate(message: &Message) -> Result<Self::Ticket, SendError>;
270
271 fn deliver(ticket: Self::Ticket) -> Result<H256, SendError>;
273}
274
275pub trait GasMeter {
276 fn maximum_dispatch_gas_used_at_most(command: &Command) -> u64;
279}
280
281pub struct ConstantGasMeter;
290
291impl GasMeter for ConstantGasMeter {
292 fn maximum_dispatch_gas_used_at_most(command: &Command) -> u64 {
293 match command {
294 Command::SetOperatingMode { .. } => 40_000,
295 Command::Upgrade { initializer, .. } => {
296 50_000 + initializer.maximum_required_gas
299 },
300 Command::UnlockNativeToken { .. } => 200_000,
301 Command::RegisterForeignToken { .. } => 1_200_000,
302 Command::MintForeignToken { .. } => 100_000,
303 Command::CallContract { gas: gas_limit, .. } => *gas_limit,
304 }
305 }
306}
307
308impl GasMeter for () {
309 fn maximum_dispatch_gas_used_at_most(_: &Command) -> u64 {
310 1
311 }
312}