Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft: refactor: Parse ERC20Treasury receipt on the vft-gateway side #176

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Cargo.lock

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

1 change: 0 additions & 1 deletion gear-programs/erc20-relay/app/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion gear-programs/erc20-relay/app/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use super::{Decode, Encode, TypeInfo};
pub enum Error {
DecodeReceiptEnvelopeFailure,
FailedEthTransaction,
NotSupportedEvent,
AlreadyProcessed,
TooOldTransaction,
SendFailure,
Expand Down
1 change: 0 additions & 1 deletion gear-programs/erc20-relay/app/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#![no_std]

pub mod abi;
pub mod error;
pub mod service;

Expand Down
62 changes: 16 additions & 46 deletions gear-programs/erc20-relay/app/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
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},
Expand Down Expand Up @@ -72,11 +71,6 @@
},
}

struct CheckedReceipt {
envelope: ReceiptEnvelope,
event: ERC20_TREASURY::Deposit,
}

pub struct Erc20Relay<'a, ExecContext> {
state: &'a RefCell<State>,
exec_context: ExecContext,
Expand Down Expand Up @@ -135,10 +129,7 @@
}

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 },
Expand Down Expand Up @@ -189,11 +180,7 @@
_ => 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);

Check failure on line 183 in gear-programs/erc20-relay/app/src/service.rs

View workflow job for this annotation

GitHub Actions / tests

this function takes 3 arguments but 1 argument was supplied

Check failure on line 183 in gear-programs/erc20-relay/app/src/service.rs

View workflow job for this annotation

GitHub Actions / tests

this function takes 3 arguments but 1 argument was supplied

Check failure on line 183 in gear-programs/erc20-relay/app/src/service.rs

View workflow job for this annotation

GitHub Actions / lints

this function takes 3 arguments but 1 argument was supplied

Check failure on line 183 in gear-programs/erc20-relay/app/src/service.rs

View workflow job for this annotation

GitHub Actions / build

this function takes 3 arguments but 1 argument was supplied
let (vft_gateway_id, reply_timeout, reply_deposit) = {
let state = self.state.borrow();

Expand All @@ -203,28 +190,29 @@
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) =

Check failure on line 193 in gear-programs/erc20-relay/app/src/service.rs

View workflow job for this annotation

GitHub Actions / tests

mismatched types

Check failure on line 193 in gear-programs/erc20-relay/app/src/service.rs

View workflow job for this annotation

GitHub Actions / lints

mismatched types

Check failure on line 193 in gear-programs/erc20-relay/app/src/service.rs

View workflow job for this annotation

GitHub Actions / build

mismatched types
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<CheckedReceipt, Error> {
fn decode_and_check_receipt(&self, message: &EthToVaraEvent) -> Result<ReceiptEnvelope, Error> {
use alloy_rlp::Decodable;

let receipt = ReceiptEnvelope::decode(&mut &message.receipt_rlp[..])
Expand All @@ -234,23 +222,8 @@
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) {
Expand All @@ -266,10 +239,7 @@
return Err(Error::TooOldTransaction);
}

Ok(CheckedReceipt {
envelope: receipt,
event,
})
Ok(receipt)
}

async fn request_checkpoint(checkpoints: ActorId, slot: u64) -> Result<H256, Error> {
Expand Down
3 changes: 3 additions & 0 deletions gear-programs/vft-gateway/app/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
alloy_sol_types::sol!(
#[allow(missing_docs)]
ERC20_TREASURY,
"./src/ERC20Treasury.json"
"./src/services/ERC20Treasury.json"
);
1 change: 1 addition & 0 deletions gear-programs/vft-gateway/app/src/services/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@ pub enum Error {
NotEthClient,
NotEnoughGas,
NoCorrespondingVaraAddress,
NotSupportedEvent,
}
41 changes: 35 additions & 6 deletions gear-programs/vft-gateway/app/src/services/mod.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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(&eth_token_id)?;
receipt_rlp: Vec<u8>,
) -> 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();

Expand All @@ -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(&eth_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,
Expand All @@ -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(
Expand Down
Loading