Skip to content

Commit

Permalink
Merge pull request #170 from multiversx/bridge-proxy-improvements
Browse files Browse the repository at this point in the history
Bridge proxy improvements
  • Loading branch information
dragos-rebegea authored Jun 27, 2024
2 parents c69ff78 + 7b1d579 commit 7f1cbd0
Show file tree
Hide file tree
Showing 13 changed files with 408 additions and 223 deletions.
238 changes: 118 additions & 120 deletions Cargo.lock

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions bridge-proxy/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ path = "../common/transaction"
[dependencies.eth-address]
path = "../common/eth-address"

[dependencies.esdt-safe]
path = "../esdt-safe"

[dependencies.multiversx-sc]
version = "=0.47.5"

Expand Down
81 changes: 32 additions & 49 deletions bridge-proxy/src/bridge-proxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ multiversx_sc::derive_imports!();

pub mod config;

use transaction::{EthTransaction, EthTransactionPayment};
use esdt_safe::ProxyTrait as _;
use transaction::EthTransaction;

#[multiversx_sc::contract]
pub trait BridgeProxyContract:
Expand All @@ -26,76 +27,58 @@ pub trait BridgeProxyContract:
#[endpoint]
fn deposit(&self, eth_tx: EthTransaction<Self::Api>) {
self.require_not_paused();
let (token_id, nonce, amount) = self.call_value().single_esdt().into_tuple();
self.eth_transaction_list()
.push_back(EthTransactionPayment {
token_id,
nonce,
amount,
eth_tx,
});
let (token_id, amount) = self.call_value().single_fungible_esdt();
require!(token_id == eth_tx.token_id, "Invalid token id");
require!(amount == eth_tx.amount, "Invalid amount");
self.pending_transactions().push(&eth_tx);
}

#[endpoint(executeWithAsnyc)]
fn execute_with_async(&self, tx_id: u32) {
fn execute_with_async(&self, tx_id: usize) {
self.require_not_paused();
let tx_node = self
.eth_transaction_list()
.remove_node_by_id(tx_id)
.unwrap_or_else(|| sc_panic!("Invalid ETH transaction!"));
let tx = tx_node.get_value_as_ref();
let tx = self.get_pending_transaction_by_id(tx_id);

require!(
tx.eth_tx.call_data.is_some(),
tx.call_data.is_some(),
"There is no data for a SC call!"
);

let call_data = unsafe { tx.eth_tx.call_data.clone().unwrap_unchecked() };
let call_data = unsafe { tx.call_data.clone().unwrap_unchecked() };
self.send()
.contract_call::<IgnoreValue>(tx.eth_tx.to.clone(), call_data.endpoint.clone())
.contract_call::<IgnoreValue>(tx.to.clone(), call_data.endpoint.clone())
.with_raw_arguments(call_data.args.clone().into())
.with_esdt_transfer((tx.token_id.clone(), tx.nonce, tx.amount.clone()))
.with_esdt_transfer((tx.token_id.clone(), 0, tx.amount.clone()))
.with_gas_limit(call_data.gas_limit)
.async_call()
.with_callback(self.callbacks().failed_execution_callback(tx))
.call_and_exit();
.async_call_promise()
.with_callback(self.callbacks().execution_callback(tx_id))
.register_promise();
}

#[callback]
fn failed_execution_callback(
#[promises_callback]
fn execution_callback(
&self,
#[call_result] result: ManagedAsyncCallResult<()>,
tx: &EthTransactionPayment<Self::Api>,
tx_id: usize,
) {
if result.is_err() {
self.eth_failed_transaction_list().push_back(tx.clone());
self.refund_transaction(tx_id);
}
self.pending_transactions().clear_entry_unchecked(tx_id);
}

#[endpoint(refundTransactions)]
fn refund_transactions(&self) -> MultiValueEncoded<EthTransactionPayment<Self::Api>> {
self.require_not_paused();
// Send Failed Tx Structure
let mut result = MultiValueEncoded::new();
for tx_loop in self.eth_failed_transaction_list().iter() {
let tx = tx_loop.get_value_cloned();
result.push(tx);
}
fn refund_transaction(&self, tx_id: usize) {
let tx = self.get_pending_transaction_by_id(tx_id);

// Send Funds
let mut all_payments = ManagedVec::new();
for failed_tx_loop in self.eth_failed_transaction_list().into_iter() {
let failed_tx = failed_tx_loop.get_value_as_ref();

all_payments.push(EsdtTokenPayment::new(
failed_tx.token_id.clone(),
failed_tx.nonce,
failed_tx.amount.clone(),
));
}
self.send()
.direct_multi(&self.multi_transfer_address().get(), &all_payments);
let _: IgnoreValue = self
.get_esdt_safe_proxy_instance()
.create_transaction(tx.from)
.with_esdt_transfer((tx.token_id.clone(), 0, tx.amount.clone()))
.execute_on_dest_context();
}

result
#[view(getPendingTransactionById)]
fn get_pending_transaction_by_id(&self, tx_id: usize) -> EthTransaction<Self::Api> {
self.pending_transactions().get_or_else(tx_id, || panic!("Invalid tx id"))
}

}
42 changes: 29 additions & 13 deletions bridge-proxy/src/config.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
multiversx_sc::imports!();
multiversx_sc::derive_imports!();

use transaction::{EthTransaction, EthTransactionPayment};
use transaction::EthTransaction;

#[multiversx_sc::module]
pub trait ConfigModule {
Expand All @@ -23,24 +23,40 @@ pub trait ConfigModule {
}
}

#[view(getEthTransactionById)]
fn get_eth_transaction_by_id(&self, id: u32) -> EthTransaction<Self::Api> {
let eth_tx_list = self.eth_transaction_list();
match eth_tx_list.get_node_by_id(id) {
Some(tx) => tx.get_value_cloned().eth_tx,
None => sc_panic!("No transaction with this id!"),
#[only_owner]
#[endpoint(setupEsdtSafe)]
fn set_esdt_safe_contract_address(
&self,
opt_esdt_safe_address: OptionalValue<ManagedAddress>,
) {
match opt_esdt_safe_address {
OptionalValue::Some(sc_addr) => {
require!(
self.blockchain().is_smart_contract(&sc_addr),
"Invalid multi-transfer address"
);
self.esdt_safe_address().set(&sc_addr);
}
OptionalValue::None => self.esdt_safe_address().clear(),
}
}

fn get_esdt_safe_proxy_instance(&self) -> esdt_safe::Proxy<Self::Api> {
self.esdt_safe_proxy(self.esdt_safe_address().get())
}

#[view(getMultiTransferAddress)]
#[storage_mapper("multiTransferAddress")]
fn multi_transfer_address(&self) -> SingleValueMapper<ManagedAddress>;

#[view(getEthTransactionList)]
#[storage_mapper("eth_transaction_list")]
fn eth_transaction_list(&self) -> LinkedListMapper<EthTransactionPayment<Self::Api>>;
#[view(getEsdtSafeAddress)]
#[storage_mapper("esdtSafeAddress")]
fn esdt_safe_address(&self) -> SingleValueMapper<ManagedAddress>;

#[proxy]
fn esdt_safe_proxy(&self, sc_address: ManagedAddress) -> esdt_safe::Proxy<Self::Api>;

#[view(getEthFailedTransactionList)]
#[storage_mapper("eth_failed_transaction_list")]
fn eth_failed_transaction_list(&self) -> LinkedListMapper<EthTransactionPayment<Self::Api>>;
#[view(getPendingTransactions)]
#[storage_mapper("pending_transactions")]
fn pending_transactions(&self) -> VecMapper<EthTransaction<Self::Api>>;
}
8 changes: 4 additions & 4 deletions bridge-proxy/tests/bridge_proxy_blackbox_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use multiversx_sc_scenario::{
};

use eth_address::*;
use transaction::{CallData, EthTransaction, EthTransactionPayment};
use transaction::{CallData, EthTransaction};

const BRIDGE_TOKEN_ID: &[u8] = b"BRIDGE-123456";
const GAS_LIMIT: u64 = 1_000_000;
Expand Down Expand Up @@ -161,7 +161,7 @@ fn deploy_deposit_test() {
test.world.sc_query(
ScQueryStep::new()
.to(&test.bridge_proxy_contract)
.call(test.bridge_proxy_contract.get_eth_transaction_by_id(1u32))
.call(test.bridge_proxy_contract.get_pending_transaction_by_id(1u32))
.expect_value(eth_tx),
);

Expand Down Expand Up @@ -251,14 +251,14 @@ fn multiple_deposit_test() {
test.world.sc_query(
ScQueryStep::new()
.to(&test.bridge_proxy_contract)
.call(test.bridge_proxy_contract.get_eth_transaction_by_id(1u32))
.call(test.bridge_proxy_contract.get_pending_transaction_by_id(1u32))
.expect_value(eth_tx1),
);

test.world.sc_query(
ScQueryStep::new()
.to(&test.bridge_proxy_contract)
.call(test.bridge_proxy_contract.get_eth_transaction_by_id(2u32))
.call(test.bridge_proxy_contract.get_pending_transaction_by_id(2u32))
.expect_value(eth_tx2),
);

Expand Down
Loading

0 comments on commit 7f1cbd0

Please sign in to comment.