Skip to content

Commit

Permalink
Refactor with alloy macro
Browse files Browse the repository at this point in the history
  • Loading branch information
yrong committed Oct 24, 2024
1 parent 2fdd374 commit 33fdc5f
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 107 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 10 additions & 12 deletions bridges/snowbridge/pallets/outbound-queue-v2/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ use frame_support::{
};
use snowbridge_core::{
inbound::Message as DeliveryMessage,
outbound::v2::{CommandWrapper, Fee, GasMeter, Message},
outbound::v2::{CommandWrapper, Fee, GasMeter, InboundMessage, Message},
BasicOperatingMode,
};
use snowbridge_merkle_tree::merkle_root;
Expand All @@ -124,11 +124,13 @@ use sp_runtime::{
ArithmeticError, DigestItem,
};
use sp_std::prelude::*;
pub use types::{CommittedMessage, FeeWithBlockNumber, ProcessMessageOriginOf};
pub use types::{FeeWithBlockNumber, ProcessMessageOriginOf};
pub use weights::WeightInfo;

pub use pallet::*;

use alloy_sol_types::SolValue;

#[frame_support::pallet]
pub mod pallet {
use super::*;
Expand Down Expand Up @@ -230,7 +232,7 @@ pub mod pallet {
/// Inspired by the `frame_system::Pallet::Events` storage value
#[pallet::storage]
#[pallet::unbounded]
pub(super) type Messages<T: Config> = StorageValue<_, Vec<CommittedMessage>, ValueQuery>;
pub(super) type Messages<T: Config> = StorageValue<_, Vec<InboundMessage>, ValueQuery>;

/// Hashes of the ABI-encoded messages in the [`Messages`] storage value. Used to generate a
/// merkle root during `on_finalize`. This storage value is killed in
Expand Down Expand Up @@ -365,21 +367,17 @@ pub mod pallet {
.into_iter()
.map(|command| CommandWrapper {
kind: command.index(),
max_dispatch_gas: T::GasMeter::maximum_dispatch_gas_used_at_most(&command),
command: command.abi_encode(),
gas: T::GasMeter::maximum_dispatch_gas_used_at_most(&command),
payload: command.abi_encode(),
})
.collect();

// Construct the final committed message
let committed_message = CommittedMessage {
origin: message.origin,
nonce,
id: message.id,
commands: commands.try_into().map_err(|_| Unsupported)?,
};
let committed_message =
InboundMessage { origin: message.origin.0.to_vec(), nonce, commands };

// ABI-encode and hash the prepared message
let message_abi_encoded = ethabi::encode(&[committed_message.clone().into()]);
let message_abi_encoded = committed_message.abi_encode();
let message_abi_encoded_hash = <T as Config>::Hashing::hash(&message_abi_encoded);

Messages::<T>::append(Box::new(committed_message.clone()));
Expand Down
41 changes: 3 additions & 38 deletions bridges/snowbridge/pallets/outbound-queue-v2/src/types.rs
Original file line number Diff line number Diff line change
@@ -1,50 +1,15 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <[email protected]>
use super::Pallet;
use codec::{Decode, Encode, MaxEncodedLen};
use ethabi::Token;
use frame_support::{pallet_prelude::ConstU32, traits::ProcessMessage, BoundedVec};
use frame_support::traits::ProcessMessage;
use scale_info::TypeInfo;
use sp_core::H256;
pub use snowbridge_merkle_tree::MerkleProof;
use sp_runtime::RuntimeDebug;
use sp_std::prelude::*;

use super::Pallet;

use snowbridge_core::outbound::v2::CommandWrapper;
pub use snowbridge_merkle_tree::MerkleProof;

pub type ProcessMessageOriginOf<T> = <Pallet<T> as ProcessMessage>::Origin;

pub const LOG_TARGET: &str = "snowbridge-outbound-queue";

/// Message which has been assigned a nonce and will be committed at the end of a block
#[derive(Encode, Decode, Clone, RuntimeDebug, TypeInfo)]
#[cfg_attr(feature = "std", derive(PartialEq))]
pub struct CommittedMessage {
/// Origin of the message
pub origin: H256,
/// Unique nonce to prevent replaying messages
pub nonce: u64,
/// MessageId
pub id: H256,
/// Commands to execute in Ethereum
pub commands: BoundedVec<CommandWrapper, ConstU32<5>>,
}

/// Convert message into an ABI-encoded form for delivery to the Gateway contract on Ethereum
impl From<CommittedMessage> for Token {
fn from(x: CommittedMessage) -> Token {
let header = vec![
Token::FixedBytes(x.origin.as_bytes().to_owned()),
Token::Uint(x.nonce.into()),
Token::Uint(x.commands.len().into()),
];
let body: Vec<Token> = x.commands.into_iter().map(|command| command.into()).collect();
let message = header.into_iter().chain(body.into_iter()).collect();
Token::Tuple(message)
}
}

/// Fee with block number for easy fetch the pending message on relayer side
#[derive(Encode, Decode, TypeInfo, Clone, Eq, PartialEq, RuntimeDebug, MaxEncodedLen)]
pub struct FeeWithBlockNumber<BlockNumber> {
Expand Down
4 changes: 4 additions & 0 deletions bridges/snowbridge/primitives/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ sp-arithmetic = { workspace = true }
snowbridge-beacon-primitives = { workspace = true }

ethabi = { workspace = true }
alloy-primitives = { features = ["rlp"], workspace = true }
alloy-sol-types = { workspace = true }

[dev-dependencies]
hex = { workspace = true, default-features = true }
Expand All @@ -40,6 +42,8 @@ xcm-executor = { workspace = true, default-features = true }
[features]
default = ["std"]
std = [
"alloy-primitives/std",
"alloy-sol-types/std",
"codec/std",
"ethabi/std",
"frame-support/std",
Expand Down
173 changes: 116 additions & 57 deletions bridges/snowbridge/primitives/core/src/outbound/v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,92 @@
//! # Outbound V2 primitives
use crate::outbound::OperatingMode;
use alloy_sol_types::sol;
use codec::{Decode, Encode};
use ethabi::Token;
use frame_support::{pallet_prelude::ConstU32, BoundedVec, PalletError};
use hex_literal::hex;
use scale_info::TypeInfo;
use sp_arithmetic::traits::{BaseArithmetic, Unsigned};
use sp_core::{RuntimeDebug, H160, H256, U256};
use sp_std::{borrow::ToOwned, vec, vec::Vec};
use sp_core::{RuntimeDebug, H160, H256};
use sp_std::{vec, vec::Vec};

use alloy_primitives::{Address, FixedBytes};
use alloy_sol_types::SolValue;

sol! {
#[derive(Encode, Decode, RuntimeDebug, TypeInfo)]
#[cfg_attr(feature = "std", derive(PartialEq))]
struct InboundMessage {
// origin
bytes origin;
// Message nonce
uint64 nonce;
// Commands
CommandWrapper[] commands;
}

#[derive(Encode, Decode, RuntimeDebug, TypeInfo)]
#[cfg_attr(feature = "std", derive(PartialEq))]
struct CommandWrapper {
uint8 kind;
uint64 gas;
bytes payload;
}

// Payload for Upgrade
struct UpgradeParams {
// The address of the implementation contract
address implAddress;
// Codehash of the new implementation contract.
bytes32 implCodeHash;
// Parameters used to upgrade storage of the gateway
bytes initParams;
}

// Payload for CreateAgent
struct CreateAgentParams {
/// @dev The agent ID of the consensus system
bytes32 agentID;
}

// Payload for SetOperatingMode instruction
struct SetOperatingModeParams {
/// The new operating mode
uint8 mode;
}

// Payload for NativeTokenUnlock instruction
struct UnlockNativeTokenParams {
// Token address
address token;
// Recipient address
address recipient;
// Amount to unlock
uint128 amount;
}

// Payload for RegisterForeignToken
struct RegisterForeignTokenParams {
/// @dev The token ID (hash of stable location id of token)
bytes32 foreignTokenID;
/// @dev The name of the token
bytes name;
/// @dev The symbol of the token
bytes symbol;
/// @dev The decimal of the token
uint8 decimals;
}

// Payload for MintForeignTokenParams instruction
struct MintForeignTokenParams {
// Foreign token ID
bytes32 foreignTokenID;
// Recipient address
address recipient;
// Amount to mint
uint128 amount;
}
}

/// A message which can be accepted by implementations of `/[`SendMessage`\]`
#[derive(Encode, Decode, TypeInfo, Clone, RuntimeDebug)]
Expand Down Expand Up @@ -87,50 +165,50 @@ impl Command {
/// Compute the enum variant index
pub fn index(&self) -> u8 {
match self {
Command::Upgrade { .. } => 1,
Command::CreateAgent { .. } => 2,
Command::SetOperatingMode { .. } => 5,
Command::UnlockNativeToken { .. } => 9,
Command::RegisterForeignToken { .. } => 10,
Command::MintForeignToken { .. } => 11,
Command::Upgrade { .. } => 0,
Command::SetOperatingMode { .. } => 1,
Command::UnlockNativeToken { .. } => 2,
Command::RegisterForeignToken { .. } => 3,
Command::MintForeignToken { .. } => 4,
Command::CreateAgent { .. } => 5,
}
}

/// ABI-encode the Command.
pub fn abi_encode(&self) -> Vec<u8> {
match self {
Command::Upgrade { impl_address, impl_code_hash, initializer, .. } =>
ethabi::encode(&[Token::Tuple(vec![
Token::Address(*impl_address),
Token::FixedBytes(impl_code_hash.as_bytes().to_owned()),
initializer.clone().map_or(Token::Bytes(vec![]), |i| Token::Bytes(i.params)),
])]),
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: initializer.clone().map_or(vec![], |i| i.params),
}
.abi_encode(),
Command::CreateAgent { agent_id } =>
ethabi::encode(&[Token::Tuple(vec![Token::FixedBytes(
agent_id.as_bytes().to_owned(),
)])]),
CreateAgentParams { agentID: FixedBytes::from(agent_id.as_fixed_bytes()) }
.abi_encode(),
Command::SetOperatingMode { mode } =>
ethabi::encode(&[Token::Tuple(vec![Token::Uint(U256::from((*mode) as u64))])]),
Command::UnlockNativeToken { agent_id, token, recipient, amount } =>
ethabi::encode(&[Token::Tuple(vec![
Token::FixedBytes(agent_id.as_bytes().to_owned()),
Token::Address(*token),
Token::Address(*recipient),
Token::Uint(U256::from(*amount)),
])]),
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 } =>
ethabi::encode(&[Token::Tuple(vec![
Token::FixedBytes(token_id.as_bytes().to_owned()),
Token::String(name.to_owned()),
Token::String(symbol.to_owned()),
Token::Uint(U256::from(*decimals)),
])]),
Command::MintForeignToken { token_id, recipient, amount } =>
ethabi::encode(&[Token::Tuple(vec![
Token::FixedBytes(token_id.as_bytes().to_owned()),
Token::Address(*recipient),
Token::Uint(U256::from(*amount)),
])]),
RegisterForeignTokenParams {
foreignTokenID: FixedBytes::from(token_id.as_fixed_bytes()),
name: name.to_vec(),
symbol: 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(),
}
}
}
Expand All @@ -145,25 +223,6 @@ pub struct Initializer {
pub maximum_required_gas: u64,
}

#[derive(Encode, Decode, Clone, RuntimeDebug, TypeInfo)]
#[cfg_attr(feature = "std", derive(PartialEq))]
pub struct CommandWrapper {
pub kind: u8,
pub max_dispatch_gas: u64,
pub command: Vec<u8>,
}

/// ABI-encoded form for delivery to the Gateway contract on Ethereum
impl From<CommandWrapper> for Token {
fn from(x: CommandWrapper) -> Token {
Token::Tuple(vec![
Token::Uint(x.kind.into()),
Token::Uint(x.max_dispatch_gas.into()),
Token::Bytes(x.command),
])
}
}

#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)]
#[cfg_attr(feature = "std", derive(PartialEq))]
/// Fee for delivering message
Expand Down

0 comments on commit 33fdc5f

Please sign in to comment.