Skip to content
This repository has been archived by the owner on Oct 22, 2024. It is now read-only.

Commit

Permalink
AgentId as user input
Browse files Browse the repository at this point in the history
  • Loading branch information
yrong committed Apr 25, 2024
1 parent 569d638 commit f4b6dba
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 97 deletions.
45 changes: 23 additions & 22 deletions bridges/snowbridge/primitives/core/src/outbound.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,19 @@ mod v1 {
// Fee multiplier
multiplier: UD60x18,
},
/// Execute a contract on the target chain
Transact {
/// ID of the agent
agent_id: H256,
/// Target contract address
target: H160,
/// The call data to the contract
payload: Vec<u8>,
/// The dynamic gas component that needs to be specified when executing the contract
gas_limit: u64,
/// The fee to cover the delivery cost
fee: u128,
},
}

impl Command {
Expand All @@ -155,6 +168,7 @@ mod v1 {
Command::TransferNativeFromAgent { .. } => 6,
Command::SetTokenTransferFees { .. } => 7,
Command::SetPricingParameters { .. } => 8,
Command::Transact { .. } => 9,
}
}

Expand Down Expand Up @@ -212,6 +226,13 @@ mod v1 {
Token::Uint(U256::from(*delivery_cost)),
Token::Uint(multiplier.clone().into_inner()),
])]),
Command::Transact { agent_id, target, payload, gas_limit, .. } =>
ethabi::encode(&[Token::Tuple(vec![
Token::FixedBytes(agent_id.as_bytes().to_owned()),
Token::Address(*target),
Token::Bytes(payload.clone()),
Token::Uint(U256::from(*gas_limit)),
])]),
}
}
}
Expand Down Expand Up @@ -239,24 +260,12 @@ mod v1 {
/// The amount of tokens to transfer
amount: u128,
},
/// Execute a contract on the target chain
Transact {
/// Target contract address
target: H160,
/// The call data to the contract
payload: Vec<u8>,
/// The dynamic gas component that needs to be specified when executing the contract
gas_limit: u64,
/// The fee to cover the delivery cost
fee: u128,
},
}

impl AgentExecuteCommand {
fn index(&self) -> u8 {
match self {
AgentExecuteCommand::TransferToken { .. } => 0,
AgentExecuteCommand::Transact { .. } => 1,
}
}

Expand All @@ -272,15 +281,6 @@ mod v1 {
Token::Uint(U256::from(*amount)),
])),
]),
AgentExecuteCommand::Transact { target, payload, gas_limit, .. } =>
ethabi::encode(&[
Token::Uint(self.index().into()),
Token::Bytes(ethabi::encode(&[
Token::Address(*target),
Token::Bytes(payload.clone()),
Token::Uint(U256::from(*gas_limit)),
])),
]),
}
}
}
Expand Down Expand Up @@ -413,7 +413,6 @@ impl GasMeter for ConstantGasMeter {
// * Assume dest account in ERC20 contract does not yet have a storage slot
// * ERC20.transferFrom possibly does other business logic besides updating balances
AgentExecuteCommand::TransferToken { .. } => 100_000,
AgentExecuteCommand::Transact { gas_limit, .. } => *gas_limit,
},
Command::Upgrade { initializer, .. } => {
let initializer_max_gas = match *initializer {
Expand All @@ -426,6 +425,7 @@ impl GasMeter for ConstantGasMeter {
},
Command::SetTokenTransferFees { .. } => 60_000,
Command::SetPricingParameters { .. } => 60_000,
Command::Transact { gas_limit, .. } => *gas_limit,
}
}
}
Expand All @@ -442,6 +442,7 @@ pub const ETHER_DECIMALS: u8 = 18;

#[derive(Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo)]
pub struct TransactInfo {
pub agent_id: H256,
pub target: H160,
pub call: Vec<u8>,
pub gas_limit: u64,
Expand Down
77 changes: 46 additions & 31 deletions bridges/snowbridge/primitives/router/src/outbound/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,36 +88,28 @@ where
SendError::MissingArgument
})?;

let mut converter = XcmConverter::new(&message, &expected_network);
let (agent_execute_command, message_id) = converter.convert().map_err(|err|{
let mut converter = XcmConverter::<AgentHashedDescription, ()>::new(
&message,
expected_network,
para_id.into(),
);
let (command, message_id) = converter.convert().map_err(|err|{
log::error!(target: "xcm::ethereum_blob_exporter", "unroutable due to pattern matching error '{err:?}'.");
SendError::Unroutable
})?;

let source_location = Location::new(1, local_sub.clone());
let agent_id = match AgentHashedDescription::convert_location(&source_location) {
Some(id) => id,
None => {
log::error!(target: "xcm::ethereum_blob_exporter", "unroutable due to not being able to create agent id. '{source_location:?}'");
return Err(SendError::Unroutable)
},
};

let channel_id: ChannelId = ParaId::from(para_id).into();

let outbound_message = Message {
id: Some(message_id.into()),
channel_id,
command: Command::AgentExecute { agent_id, command: agent_execute_command.clone() },
};
let outbound_message =
Message { id: Some(message_id.into()), channel_id, command: command.clone() };

// validate the message
let (ticket, fees) = OutboundQueue::validate(&outbound_message).map_err(|err| {
log::error!(target: "xcm::ethereum_blob_exporter", "OutboundQueue validation of message failed. {err:?}");
SendError::Unroutable
})?;
let fee = match agent_execute_command {
AgentExecuteCommand::Transact { fee, .. } => {
let fee = match command {
Command::Transact { fee, .. } => {
ensure!(fee > fees.remote, SendError::Fees);
Ok::<Assets, SendError>(Asset::from((Location::parent(), fees.local)).into())
},
Expand Down Expand Up @@ -163,6 +155,7 @@ enum XcmConverterError {
TransactSovereignAccountExpected,
TransactDecodeFailed,
UnexpectedInstruction,
Unroutable,
}

macro_rules! match_expression {
Expand All @@ -174,17 +167,28 @@ macro_rules! match_expression {
};
}

struct XcmConverter<'a, Call> {
struct XcmConverter<'a, AgentHashedDescription, Call> {
iter: Peekable<Iter<'a, Instruction<Call>>>,
ethereum_network: &'a NetworkId,
ethereum_network: NetworkId,
para_id: ParaId,
_marker: PhantomData<AgentHashedDescription>,
}
impl<'a, Call> XcmConverter<'a, Call> {
fn new(message: &'a Xcm<Call>, ethereum_network: &'a NetworkId) -> Self {
Self { iter: message.inner().iter().peekable(), ethereum_network }
impl<'a, AgentHashedDescription, Call> XcmConverter<'a, AgentHashedDescription, Call>
where
AgentHashedDescription: ConvertLocation<H256>,
{
fn new(message: &'a Xcm<Call>, ethereum_network: NetworkId, para_id: ParaId) -> Self {
Self {
iter: message.inner().iter().peekable(),
ethereum_network,
para_id,
_marker: Default::default(),
}
}

fn convert(&mut self) -> Result<(AgentExecuteCommand, [u8; 32]), XcmConverterError> {
fn convert(&mut self) -> Result<(Command, [u8; 32]), XcmConverterError> {
let result = match self.peek() {
// Transact message
Ok(Transact { .. }) => self.transact_message(),
// Get withdraw/deposit and make native tokens create message.
Ok(WithdrawAsset { .. }) => self.native_tokens_unlock_message(),
Expand All @@ -200,7 +204,7 @@ impl<'a, Call> XcmConverter<'a, Call> {
Ok(result)
}

fn transact_message(&mut self) -> Result<(AgentExecuteCommand, [u8; 32]), XcmConverterError> {
fn transact_message(&mut self) -> Result<(Command, [u8; 32]), XcmConverterError> {
let call_data = if let Transact { origin_kind, call, .. } = self.next()? {
ensure!(
*origin_kind == OriginKind::SovereignAccount,
Expand All @@ -216,7 +220,8 @@ impl<'a, Call> XcmConverter<'a, Call> {

let topic_id = match_expression!(self.next()?, SetTopic(id), id).ok_or(SetTopicExpected)?;
Ok((
AgentExecuteCommand::Transact {
Command::Transact {
agent_id: message.agent_id,
target: message.target,
payload: message.call,
gas_limit: message.gas_limit,
Expand All @@ -226,9 +231,7 @@ impl<'a, Call> XcmConverter<'a, Call> {
))
}

fn native_tokens_unlock_message(
&mut self,
) -> Result<(AgentExecuteCommand, [u8; 32]), XcmConverterError> {
fn native_tokens_unlock_message(&mut self) -> Result<(Command, [u8; 32]), XcmConverterError> {
use XcmConverterError::*;

// Get the reserve assets from WithdrawAsset.
Expand Down Expand Up @@ -302,7 +305,19 @@ impl<'a, Call> XcmConverter<'a, Call> {
// Check if there is a SetTopic and skip over it if found.
let topic_id = match_expression!(self.next()?, SetTopic(id), id).ok_or(SetTopicExpected)?;

Ok((AgentExecuteCommand::TransferToken { token, recipient, amount }, *topic_id))
let agent_id = AgentHashedDescription::convert_location(&Location::new(
1,
Parachain(self.para_id.into()),
))
.ok_or(Unroutable)?;

Ok((
Command::AgentExecute {
agent_id,
command: AgentExecuteCommand::TransferToken { token, recipient, amount },
},
*topic_id,
))
}

fn next(&mut self) -> Result<&'a Instruction<Call>, XcmConverterError> {
Expand All @@ -315,7 +330,7 @@ impl<'a, Call> XcmConverter<'a, Call> {

fn network_matches(&self, network: &Option<NetworkId>) -> bool {
if let Some(network) = network {
network == self.ethereum_network
network.clone() == self.ethereum_network
} else {
true
}
Expand Down
Loading

0 comments on commit f4b6dba

Please sign in to comment.