From 54ad775892f7673b4c2080adac313d41c1fef89b Mon Sep 17 00:00:00 2001 From: Georgy Shepelev Date: Thu, 24 Oct 2024 15:29:10 +0400 Subject: [PATCH] initial --- Cargo.lock | 4 +- gear-programs/erc20-relay/app/Cargo.toml | 1 - gear-programs/erc20-relay/app/src/error.rs | 1 - gear-programs/erc20-relay/app/src/lib.rs | 1 - gear-programs/erc20-relay/app/src/service.rs | 62 +++++-------------- gear-programs/vft-gateway/app/Cargo.toml | 3 + .../app/src/services}/ERC20Treasury.json | 0 .../app/src/services}/abi.rs | 2 +- .../vft-gateway/app/src/services/error.rs | 1 + .../vft-gateway/app/src/services/mod.rs | 41 ++++++++++-- 10 files changed, 59 insertions(+), 57 deletions(-) rename gear-programs/{erc20-relay/app/src => vft-gateway/app/src/services}/ERC20Treasury.json (100%) rename gear-programs/{erc20-relay/app/src => vft-gateway/app/src/services}/abi.rs (64%) diff --git a/Cargo.lock b/Cargo.lock index b5adef70..22eb756c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3774,7 +3774,6 @@ name = "erc20-relay-app" version = "0.1.0" dependencies = [ "alloy-rlp", - "alloy-sol-types", "checkpoint_light_client-io", "erc20-relay", "erc20-relay-client", @@ -15387,6 +15386,9 @@ dependencies = [ name = "vft-gateway-app" version = "0.1.0" dependencies = [ + "alloy-rlp", + "alloy-sol-types", + "ethereum-common", "gbuiltin-eth-bridge", "git-download", "gstd 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/gear-programs/erc20-relay/app/Cargo.toml b/gear-programs/erc20-relay/app/Cargo.toml index 55f84f82..f0fd8f25 100644 --- a/gear-programs/erc20-relay/app/Cargo.toml +++ b/gear-programs/erc20-relay/app/Cargo.toml @@ -5,7 +5,6 @@ edition.workspace = true [dependencies] alloy-rlp.workspace = true -alloy-sol-types = { workspace = true, features = ["json"] } checkpoint_light_client-io.workspace = true ethereum-common.workspace = true sails-rs.workspace = true diff --git a/gear-programs/erc20-relay/app/src/error.rs b/gear-programs/erc20-relay/app/src/error.rs index 3645783a..08aca2c8 100644 --- a/gear-programs/erc20-relay/app/src/error.rs +++ b/gear-programs/erc20-relay/app/src/error.rs @@ -6,7 +6,6 @@ use super::{Decode, Encode, TypeInfo}; pub enum Error { DecodeReceiptEnvelopeFailure, FailedEthTransaction, - NotSupportedEvent, AlreadyProcessed, TooOldTransaction, SendFailure, diff --git a/gear-programs/erc20-relay/app/src/lib.rs b/gear-programs/erc20-relay/app/src/lib.rs index 08ff904b..7675ff7e 100644 --- a/gear-programs/erc20-relay/app/src/lib.rs +++ b/gear-programs/erc20-relay/app/src/lib.rs @@ -1,6 +1,5 @@ #![no_std] -pub mod abi; pub mod error; pub mod service; diff --git a/gear-programs/erc20-relay/app/src/service.rs b/gear-programs/erc20-relay/app/src/service.rs index cf9a76a6..9a1aa127 100644 --- a/gear-programs/erc20-relay/app/src/service.rs +++ b/gear-programs/erc20-relay/app/src/service.rs @@ -4,8 +4,7 @@ mod vft { include!(concat!(env!("OUT_DIR"), "/vft-gateway.rs")); } -use super::{abi::ERC20_TREASURY, error::Error, BTreeSet, Config, ExecContext, RefCell, State}; -use alloy_sol_types::SolEvent; +use super::{error::Error, BTreeSet, Config, ExecContext, RefCell, State}; use checkpoint_light_client_io::{Handle, HandleResult}; use ethereum_common::{ beacon::{light::Block as LightBeaconBlock, BlockHeader as BeaconBlockHeader}, @@ -72,11 +71,6 @@ enum Event { }, } -struct CheckedReceipt { - envelope: ReceiptEnvelope, - event: ERC20_TREASURY::Deposit, -} - pub struct Erc20Relay<'a, ExecContext> { state: &'a RefCell, exec_context: ExecContext, @@ -135,10 +129,7 @@ where } pub async fn relay(&mut self, message: EthToVaraEvent) -> Result<(), Error> { - let CheckedReceipt { - envelope: receipt, - event, - } = self.decode_and_check_receipt(&message)?; + let receipt = self.decode_and_check_receipt(&message)?; let EthToVaraEvent { proof_block: BlockInclusionProof { block, mut headers }, @@ -189,11 +180,7 @@ where _ => return Err(Error::InvalidReceiptProof), } - let amount = U256::from_little_endian(event.amount.as_le_slice()); - let receiver = ActorId::from(event.to.0); - let fungible_token = H160::from(event.token.0 .0); - let call_payload = - vft_gateway::io::MintTokens::encode_call(fungible_token, receiver, amount); + let call_payload = vft_gateway::io::MintTokens::encode_call(message.receipt_rlp); let (vft_gateway_id, reply_timeout, reply_deposit) = { let state = self.state.borrow(); @@ -203,28 +190,29 @@ where state.config.reply_deposit, ) }; - gstd::msg::send_bytes_for_reply(vft_gateway_id, call_payload, 0, reply_deposit) - .map_err(|_| Error::SendFailure)? - .up_to(Some(reply_timeout)) - .map_err(|_| Error::ReplyTimeout)? - .handle_reply(move || handle_reply(slot, transaction_index)) - .map_err(|_| Error::ReplyHook)? - .await - .map_err(|_| Error::ReplyFailure)?; + let (fungible_token, receiver, amount) = + gstd::msg::send_bytes_for_reply(vft_gateway_id, call_payload, 0, reply_deposit) + .map_err(|_| Error::SendFailure)? + .up_to(Some(reply_timeout)) + .map_err(|_| Error::ReplyTimeout)? + .handle_reply(move || handle_reply(slot, transaction_index)) + .map_err(|_| Error::ReplyHook)? + .await + .map_err(|_| Error::ReplyFailure)?; let _ = self.notify_on(Event::Relayed { slot, block_number: block.body.execution_payload.block_number, transaction_index: transaction_index as u32, fungible_token, - to: ActorId::from(event.to.0), + to: receiver, amount, }); Ok(()) } - fn decode_and_check_receipt(&self, message: &EthToVaraEvent) -> Result { + fn decode_and_check_receipt(&self, message: &EthToVaraEvent) -> Result { use alloy_rlp::Decodable; let receipt = ReceiptEnvelope::decode(&mut &message.receipt_rlp[..]) @@ -234,23 +222,8 @@ where return Err(Error::FailedEthTransaction); } - let slot = message.proof_block.block.slot; - let state = self.state.borrow_mut(); - // decode log and check that it is from an allowed address - let event = receipt - .logs() - .iter() - .find_map(|log| { - let eth_address = H160::from(log.address.0 .0); - let Ok(event) = ERC20_TREASURY::Deposit::decode_log_data(log, true) else { - return None; - }; - - (eth_address == state.address).then_some(event) - }) - .ok_or(Error::NotSupportedEvent)?; - // check for double spending + let slot = message.proof_block.block.slot; let transactions = transactions_mut(); let key = (slot, message.transaction_index); if transactions.contains(&key) { @@ -266,10 +239,7 @@ where return Err(Error::TooOldTransaction); } - Ok(CheckedReceipt { - envelope: receipt, - event, - }) + Ok(receipt) } async fn request_checkpoint(checkpoints: ActorId, slot: u64) -> Result { diff --git a/gear-programs/vft-gateway/app/Cargo.toml b/gear-programs/vft-gateway/app/Cargo.toml index 8ff7d707..4814e8a3 100644 --- a/gear-programs/vft-gateway/app/Cargo.toml +++ b/gear-programs/vft-gateway/app/Cargo.toml @@ -7,6 +7,9 @@ edition.workspace = true sails-rs.workspace = true parity-scale-codec.workspace = true scale-info.workspace = true +alloy-rlp.workspace = true +alloy-sol-types.workspace = true +ethereum-common.workspace = true gstd.workspace = true gbuiltin-eth-bridge.workspace = true vft-client.workspace = true diff --git a/gear-programs/erc20-relay/app/src/ERC20Treasury.json b/gear-programs/vft-gateway/app/src/services/ERC20Treasury.json similarity index 100% rename from gear-programs/erc20-relay/app/src/ERC20Treasury.json rename to gear-programs/vft-gateway/app/src/services/ERC20Treasury.json diff --git a/gear-programs/erc20-relay/app/src/abi.rs b/gear-programs/vft-gateway/app/src/services/abi.rs similarity index 64% rename from gear-programs/erc20-relay/app/src/abi.rs rename to gear-programs/vft-gateway/app/src/services/abi.rs index 2620aaa5..c2789959 100644 --- a/gear-programs/erc20-relay/app/src/abi.rs +++ b/gear-programs/vft-gateway/app/src/services/abi.rs @@ -1,5 +1,5 @@ alloy_sol_types::sol!( #[allow(missing_docs)] ERC20_TREASURY, - "./src/ERC20Treasury.json" + "./src/services/ERC20Treasury.json" ); diff --git a/gear-programs/vft-gateway/app/src/services/error.rs b/gear-programs/vft-gateway/app/src/services/error.rs index 04b8059f..e8cabacc 100644 --- a/gear-programs/vft-gateway/app/src/services/error.rs +++ b/gear-programs/vft-gateway/app/src/services/error.rs @@ -24,4 +24,5 @@ pub enum Error { NotEthClient, NotEnoughGas, NoCorrespondingVaraAddress, + NotSupportedEvent, } diff --git a/gear-programs/vft-gateway/app/src/services/mod.rs b/gear-programs/vft-gateway/app/src/services/mod.rs index 49e44880..5056df61 100644 --- a/gear-programs/vft-gateway/app/src/services/mod.rs +++ b/gear-programs/vft-gateway/app/src/services/mod.rs @@ -1,6 +1,7 @@ use collections::HashMap; use sails_rs::{gstd::ExecContext, prelude::*}; +mod abi; mod bridge_builtin_operations; pub mod error; pub mod msg_tracker; @@ -147,11 +148,13 @@ where pub async fn mint_tokens( &mut self, - eth_token_id: H160, - receiver: ActorId, - amount: U256, - ) -> Result<(), Error> { - let vara_token_id = self.get_vara_token_id(ð_token_id)?; + receipt_rlp: Vec, + ) -> Result<(H160, ActorId, U256), Error> { + use abi::ERC20_TREASURY; + use alloy_rlp::Decodable; + use alloy_sol_types::SolEvent; + use ethereum_common::utils::ReceiptEnvelope; + let data = self.data(); let sender = self.exec_context.actor_id(); @@ -168,6 +171,29 @@ where return Err(Error::NotEnoughGas); } + let receipt = + ReceiptEnvelope::decode(&mut &receipt_rlp[..]).map_err(|_| Error::NotSupportedEvent)?; + + if !receipt.is_success() { + return Err(Error::NotSupportedEvent); + } + + // decode log and check that it is from an allowed address + let (vara_token_id, event) = receipt + .logs() + .iter() + .find_map(|log| { + let eth_token_id = H160::from(log.address.0 .0); + let vara_token_id = self.get_vara_token_id(ð_token_id).ok()?; + let event = ERC20_TREASURY::Deposit::decode_log_data(log, true).ok()?; + + Some((vara_token_id, event)) + }) + .ok_or(Error::NotSupportedEvent)?; + + let amount = U256::from_little_endian(event.amount.as_le_slice()); + let receiver = ActorId::from(event.to.0); + let fungible_token = H160::from(event.token.0 .0); let msg_id = gstd::msg::id(); let transaction_details = TxDetails::MintTokens { vara_token_id, @@ -180,7 +206,10 @@ where transaction_details, ); utils::set_critical_hook(msg_id); - token_operations::mint_tokens(vara_token_id, receiver, amount, config, msg_id).await + + token_operations::mint_tokens(vara_token_id, receiver, amount, config, msg_id) + .await + .map(|_| (fungible_token, receiver, amount)) } pub async fn transfer_vara_to_eth(