1use crate::{OperatingMode, SendError, SendMessageFeeProvider};
6use codec::{Decode, DecodeWithMemTracking, Encode};
7use ethabi::Token;
8use scale_info::TypeInfo;
9use snowbridge_core::{pricing::UD60x18, ChannelId};
10use sp_arithmetic::traits::{BaseArithmetic, Unsigned};
11use sp_core::{H160, H256, U256};
12use sp_std::{borrow::ToOwned, vec, vec::Vec};
13
14#[derive(Encode, Decode, TypeInfo, Clone, Debug)]
17#[cfg_attr(feature = "std", derive(PartialEq))]
18pub enum VersionedQueuedMessage {
19 V1(QueuedMessage),
20}
21
22impl TryFrom<VersionedQueuedMessage> for QueuedMessage {
23 type Error = ();
24 fn try_from(x: VersionedQueuedMessage) -> Result<Self, Self::Error> {
25 use VersionedQueuedMessage::*;
26 match x {
27 V1(x) => Ok(x),
28 }
29 }
30}
31
32impl<T: Into<QueuedMessage>> From<T> for VersionedQueuedMessage {
33 fn from(x: T) -> Self {
34 VersionedQueuedMessage::V1(x.into())
35 }
36}
37
38#[derive(Encode, Decode, TypeInfo, Clone, Debug)]
40#[cfg_attr(feature = "std", derive(PartialEq))]
41pub struct Message {
42 pub id: Option<H256>,
49 pub channel_id: ChannelId,
51 pub command: Command,
53}
54
55#[derive(Clone, Encode, Decode, Debug, TypeInfo)]
57#[cfg_attr(feature = "std", derive(PartialEq))]
58pub enum Command {
59 AgentExecute {
63 agent_id: H256,
65 command: AgentExecuteCommand,
67 },
68 Upgrade {
70 impl_address: H160,
72 impl_code_hash: H256,
74 initializer: Option<Initializer>,
76 },
77 SetOperatingMode {
79 mode: OperatingMode,
81 },
82 SetTokenTransferFees {
84 create_asset_xcm: u128,
86 transfer_asset_xcm: u128,
88 register_token: U256,
90 },
91 SetPricingParameters {
93 exchange_rate: UD60x18,
95 delivery_cost: u128,
97 multiplier: UD60x18,
99 },
100 UnlockNativeToken {
102 agent_id: H256,
104 token: H160,
106 recipient: H160,
108 amount: u128,
110 },
111 RegisterForeignToken {
113 token_id: H256,
115 name: Vec<u8>,
117 symbol: Vec<u8>,
119 decimals: u8,
121 },
122 MintForeignToken {
124 token_id: H256,
126 recipient: H160,
128 amount: u128,
130 },
131}
132
133impl Command {
134 pub fn index(&self) -> u8 {
136 match self {
137 Command::AgentExecute { .. } => 0,
138 Command::Upgrade { .. } => 1,
139 Command::SetOperatingMode { .. } => 5,
140 Command::SetTokenTransferFees { .. } => 7,
141 Command::SetPricingParameters { .. } => 8,
142 Command::UnlockNativeToken { .. } => 9,
143 Command::RegisterForeignToken { .. } => 10,
144 Command::MintForeignToken { .. } => 11,
145 }
146 }
147
148 pub fn abi_encode(&self) -> Vec<u8> {
150 match self {
151 Command::AgentExecute { agent_id, command } => ethabi::encode(&[Token::Tuple(vec![
152 Token::FixedBytes(agent_id.as_bytes().to_owned()),
153 Token::Bytes(command.abi_encode()),
154 ])]),
155 Command::Upgrade { impl_address, impl_code_hash, initializer, .. } => {
156 ethabi::encode(&[Token::Tuple(vec![
157 Token::Address(*impl_address),
158 Token::FixedBytes(impl_code_hash.as_bytes().to_owned()),
159 initializer.clone().map_or(Token::Bytes(vec![]), |i| Token::Bytes(i.params)),
160 ])])
161 },
162 Command::SetOperatingMode { mode } => {
163 ethabi::encode(&[Token::Tuple(vec![Token::Uint(U256::from((*mode) as u64))])])
164 },
165 Command::SetTokenTransferFees {
166 create_asset_xcm,
167 transfer_asset_xcm,
168 register_token,
169 } => ethabi::encode(&[Token::Tuple(vec![
170 Token::Uint(U256::from(*create_asset_xcm)),
171 Token::Uint(U256::from(*transfer_asset_xcm)),
172 Token::Uint(*register_token),
173 ])]),
174 Command::SetPricingParameters { exchange_rate, delivery_cost, multiplier } => {
175 ethabi::encode(&[Token::Tuple(vec![
176 Token::Uint(exchange_rate.clone().into_inner()),
177 Token::Uint(U256::from(*delivery_cost)),
178 Token::Uint(multiplier.clone().into_inner()),
179 ])])
180 },
181 Command::UnlockNativeToken { agent_id, token, recipient, amount } => {
182 ethabi::encode(&[Token::Tuple(vec![
183 Token::FixedBytes(agent_id.as_bytes().to_owned()),
184 Token::Address(*token),
185 Token::Address(*recipient),
186 Token::Uint(U256::from(*amount)),
187 ])])
188 },
189 Command::RegisterForeignToken { token_id, name, symbol, decimals } => {
190 ethabi::encode(&[Token::Tuple(vec![
191 Token::FixedBytes(token_id.as_bytes().to_owned()),
192 Token::String(name.to_owned()),
193 Token::String(symbol.to_owned()),
194 Token::Uint(U256::from(*decimals)),
195 ])])
196 },
197 Command::MintForeignToken { token_id, recipient, amount } => {
198 ethabi::encode(&[Token::Tuple(vec![
199 Token::FixedBytes(token_id.as_bytes().to_owned()),
200 Token::Address(*recipient),
201 Token::Uint(U256::from(*amount)),
202 ])])
203 },
204 }
205 }
206}
207
208#[derive(Clone, Encode, Decode, DecodeWithMemTracking, PartialEq, Debug, TypeInfo)]
211pub struct Initializer {
212 pub params: Vec<u8>,
214 pub maximum_required_gas: u64,
216}
217
218#[derive(Clone, Encode, Decode, Debug, TypeInfo)]
220#[cfg_attr(feature = "std", derive(PartialEq))]
221pub enum AgentExecuteCommand {
222 TransferToken {
224 token: H160,
226 recipient: H160,
228 amount: u128,
230 },
231}
232
233impl AgentExecuteCommand {
234 fn index(&self) -> u8 {
235 match self {
236 AgentExecuteCommand::TransferToken { .. } => 0,
237 }
238 }
239
240 pub fn abi_encode(&self) -> Vec<u8> {
242 match self {
243 AgentExecuteCommand::TransferToken { token, recipient, amount } => ethabi::encode(&[
244 Token::Uint(self.index().into()),
245 Token::Bytes(ethabi::encode(&[
246 Token::Address(*token),
247 Token::Address(*recipient),
248 Token::Uint(U256::from(*amount)),
249 ])),
250 ]),
251 }
252 }
253}
254
255#[derive(Clone, Encode, Decode, Debug, TypeInfo)]
257#[cfg_attr(feature = "std", derive(PartialEq))]
258pub struct QueuedMessage {
259 pub id: H256,
261 pub channel_id: ChannelId,
263 pub command: Command,
265}
266
267#[derive(Clone, Encode, Decode, Debug, TypeInfo)]
268#[cfg_attr(feature = "std", derive(PartialEq))]
269pub struct Fee<Balance>
271where
272 Balance: BaseArithmetic + Unsigned + Copy,
273{
274 pub local: Balance,
276 pub remote: Balance,
278}
279
280impl<Balance> Fee<Balance>
281where
282 Balance: BaseArithmetic + Unsigned + Copy,
283{
284 pub fn total(&self) -> Balance {
285 self.local.saturating_add(self.remote)
286 }
287}
288
289impl<Balance> From<(Balance, Balance)> for Fee<Balance>
290where
291 Balance: BaseArithmetic + Unsigned + Copy,
292{
293 fn from((local, remote): (Balance, Balance)) -> Self {
294 Self { local, remote }
295 }
296}
297
298pub trait SendMessage: SendMessageFeeProvider {
300 type Ticket: Clone + Encode + Decode;
301
302 fn validate(
306 message: &Message,
307 ) -> Result<(Self::Ticket, Fee<<Self as SendMessageFeeProvider>::Balance>), SendError>;
308
309 fn deliver(ticket: Self::Ticket) -> Result<H256, SendError>;
311}
312
313pub trait Ticket: Encode + Decode + Clone {
314 fn message_id(&self) -> H256;
315}
316
317pub trait GasMeter {
318 const MAXIMUM_BASE_GAS: u64;
321
322 fn maximum_gas_used_at_most(command: &Command) -> u64 {
324 Self::MAXIMUM_BASE_GAS + Self::maximum_dispatch_gas_used_at_most(command)
325 }
326
327 fn maximum_dispatch_gas_used_at_most(command: &Command) -> u64;
330}
331
332pub struct ConstantGasMeter;
341
342impl GasMeter for ConstantGasMeter {
343 const MAXIMUM_BASE_GAS: u64 = 185_000;
347
348 fn maximum_dispatch_gas_used_at_most(command: &Command) -> u64 {
349 match command {
350 Command::SetOperatingMode { .. } => 40_000,
351 Command::AgentExecute { command, .. } => match command {
352 AgentExecuteCommand::TransferToken { .. } => 200_000,
359 },
360 Command::Upgrade { initializer, .. } => {
361 let initializer_max_gas = match *initializer {
362 Some(Initializer { maximum_required_gas, .. }) => maximum_required_gas,
363 None => 0,
364 };
365 50_000 + initializer_max_gas
368 },
369 Command::SetTokenTransferFees { .. } => 60_000,
370 Command::SetPricingParameters { .. } => 60_000,
371 Command::UnlockNativeToken { .. } => 200_000,
372 Command::RegisterForeignToken { .. } => 1_200_000,
373 Command::MintForeignToken { .. } => 100_000,
374 }
375 }
376}
377
378impl GasMeter for () {
379 const MAXIMUM_BASE_GAS: u64 = 1;
380
381 fn maximum_dispatch_gas_used_at_most(_: &Command) -> u64 {
382 1
383 }
384}
385
386pub const ETHER_DECIMALS: u8 = 18;