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

EthTransaction: Add refund address #257

Draft
wants to merge 4 commits into
base: v3.5-audit-fixes
Choose a base branch
from
Draft
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
49 changes: 31 additions & 18 deletions bridge-proxy/src/bridge-proxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,22 +103,6 @@ pub trait BridgeProxyContract:
tx_call.register_promise();
}

// TODO: will activate endpoint in a future release
// #[endpoint(cancel)]
fn cancel(&self, tx_id: usize) {
let tx_start_round = self.ongoing_execution(tx_id).get();
let current_block_round = self.blockchain().get_block_round();
require!(
current_block_round - tx_start_round > DELAY_BEFORE_OWNER_CAN_CANCEL_TRANSACTION,
"Transaction can't be cancelled yet"
);

let tx = self.get_pending_transaction_by_id(tx_id);
let payment = self.payments(tx_id).get();
self.tx().to(tx.to).payment(payment).transfer();
self.cleanup_transaction(tx_id);
}

#[promises_callback]
fn execution_callback(&self, #[call_result] result: ManagedAsyncCallResult<()>, tx_id: usize) {
if result.is_err() {
Expand All @@ -128,8 +112,8 @@ pub trait BridgeProxyContract:
self.cleanup_transaction(tx_id);
}

#[endpoint(refundTransaction)]
fn refund_transaction(&self, tx_id: usize) {
#[endpoint(refundTransactionToEthereum)]
fn refund_transaction_to_ethereum(&self, tx_id: usize) {
let tx = self.refund_transactions(tx_id).get();
let esdt_safe_contract_address = self.get_esdt_safe_address();

Expand All @@ -154,6 +138,35 @@ pub trait BridgeProxyContract:
.sync_call();
}

#[endpoint(claimBridgedTokensAfterFailedRefund)]
fn claim_bridged_tokens_after_failed_refund(&self, tx_id: usize) {
let refund_transactions_mapper = self.refund_transactions(tx_id);
require!(
!refund_transactions_mapper.is_empty(),
"No transaction with this ID"
);

let tx_start_round = self.ongoing_execution(tx_id).get();
let current_block_round = self.blockchain().get_block_round();
require!(
current_block_round - tx_start_round > DELAY_BEFORE_OWNER_CAN_CANCEL_TRANSACTION,
"Transaction can't be cancelled yet"
);

let tx = refund_transactions_mapper.get();
let caller = self.blockchain().get_caller();

require!(
caller == tx.refund_address,
"Caller was not whitelisted as refund address"
);

let payments = self.payments(tx_id).get();

self.tx().to(ToCaller).esdt(payments).transfer();
self.cleanup_transaction(tx_id);
}

fn unwrap_token(&self, requested_token: &TokenIdentifier, tx_id: usize) -> EsdtTokenPayment {
let payment = self.payments(tx_id).get();
let bridged_tokens_wrapper_address = self.get_bridged_tokens_wrapper_address();
Expand Down
14 changes: 12 additions & 2 deletions bridge-proxy/tests/bridge_proxy_blackbox_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ const USER1_ADDRESS: TestAddress = TestAddress::new("user1");
const USER2_ADDRESS: TestAddress = TestAddress::new("user2");
const RELAYER1_ADDRESS: TestAddress = TestAddress::new("relayer1");
const RELAYER2_ADDRESS: TestAddress = TestAddress::new("relayer2");
const REFUND_ADDRESS: TestAddress = TestAddress::new("refund_addr");

fn world() -> ScenarioWorld {
let mut blockchain = ScenarioWorld::new();
Expand Down Expand Up @@ -294,6 +295,7 @@ fn bridge_proxy_execute_crowdfunding_test() {
raw_addr: ManagedByteArray::new_from_bytes(b"01020304050607080910"),
},
to: ManagedAddress::from(CROWDFUNDING_ADDRESS.eval_to_array()),
refund_address: ManagedAddress::from(REFUND_ADDRESS.eval_to_array()),
token_id: BRIDGE_TOKEN_ID.into(),
amount: BigUint::from(500u64),
tx_nonce: 1u64,
Expand Down Expand Up @@ -362,6 +364,7 @@ fn multiple_deposit_test() {
raw_addr: ManagedByteArray::new_from_bytes(b"01020304050607080910"),
},
to: ManagedAddress::from(CROWDFUNDING_ADDRESS.eval_to_array()),
refund_address: ManagedAddress::from(REFUND_ADDRESS.eval_to_array()),
token_id: BRIDGE_TOKEN_ID.into(),
amount: BigUint::from(500u64),
tx_nonce: 1u64,
Expand All @@ -373,6 +376,7 @@ fn multiple_deposit_test() {
raw_addr: ManagedByteArray::new_from_bytes(b"01020304050607080910"),
},
to: ManagedAddress::from(CROWDFUNDING_ADDRESS.eval_to_array()),
refund_address: ManagedAddress::from(REFUND_ADDRESS.eval_to_array()),
token_id: BRIDGE_TOKEN_ID.into(),
amount: BigUint::from(500u64),
tx_nonce: 2u64,
Expand Down Expand Up @@ -482,6 +486,7 @@ fn test_highest_tx_id() {
raw_addr: ManagedByteArray::new_from_bytes(b"01020304050607080910"),
},
to: ManagedAddress::from(CROWDFUNDING_ADDRESS.eval_to_array()),
refund_address: ManagedAddress::from(REFUND_ADDRESS.eval_to_array()),
token_id: BRIDGE_TOKEN_ID.into(),
amount: BigUint::from(5u64),
tx_nonce: i as u64,
Expand Down Expand Up @@ -551,6 +556,7 @@ fn bridge_proxy_wrong_formatting_sc_call_test() {
raw_addr: ManagedByteArray::new_from_bytes(b"01020304050607080910"),
},
to: ManagedAddress::from(NO_INIT_SC_ADDRESS.eval_to_array()),
refund_address: ManagedAddress::from(REFUND_ADDRESS.eval_to_array()),
token_id: BRIDGE_TOKEN_ID.into(),
amount: BigUint::from(500u64),
tx_nonce: 1u64,
Expand Down Expand Up @@ -609,6 +615,7 @@ fn bridge_proxy_wrong_formatting_sc_call_test() {
raw_addr: ManagedByteArray::new_from_bytes(b"01020304050607080910"),
},
to: ManagedAddress::from(CROWDFUNDING_ADDRESS.eval_to_array()),
refund_address: ManagedAddress::from(REFUND_ADDRESS.eval_to_array()),
token_id: BRIDGE_TOKEN_ID.into(),
amount: amount.clone(),
tx_nonce: 2u64,
Expand Down Expand Up @@ -667,6 +674,7 @@ fn bridge_proxy_wrong_formatting_sc_call_test() {
raw_addr: ManagedByteArray::new_from_bytes(b"01020304050607080910"),
},
to: ManagedAddress::from(CROWDFUNDING_ADDRESS.eval_to_array()),
refund_address: ManagedAddress::from(REFUND_ADDRESS.eval_to_array()),
token_id: BRIDGE_TOKEN_ID.into(),
amount: amount.clone(),
tx_nonce: 3u64,
Expand Down Expand Up @@ -734,6 +742,7 @@ fn bridge_proxy_too_small_gas_sc_call_test() {
raw_addr: ManagedByteArray::new_from_bytes(b"01020304050607080910"),
},
to: ManagedAddress::from(CROWDFUNDING_ADDRESS.eval_to_array()),
refund_address: ManagedAddress::from(REFUND_ADDRESS.eval_to_array()),
token_id: BRIDGE_TOKEN_ID.into(),
amount: BigUint::from(500u64),
tx_nonce: 1u64,
Expand Down Expand Up @@ -773,7 +782,7 @@ fn bridge_proxy_too_small_gas_sc_call_test() {

test.world
.check_account(BRIDGE_PROXY_ADDRESS)
.check_storage("str:refundTransactions|u32:1", "0x30313032303330343035303630373038303931300000000000000000050063726f7766756e64696e675f5f5f5f5f5f5f5f5f5f5f0000000d4252494447452d3132333435360000000201f4000000000000000101000000150000000466756e6400000000000f42400100000000")
.check_storage("str:refundTransactions|u32:1", "0x30313032303330343035303630373038303931300000000000000000050063726f7766756e64696e675f5f5f5f5f5f5f5f5f5f5f726566756e645f616464725f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f0000000d4252494447452d3132333435360000000201f4000000000000000101000000150000000466756e6400000000000f42400100000000")
.check_storage("str:batchId|u32:1", "1")
.check_storage("str:highestTxId", "1")
.check_storage("str:payments|u32:1", "nested:str:BRIDGE-123456|u64:0|biguint:500");
Expand Down Expand Up @@ -805,6 +814,7 @@ fn bridge_proxy_empty_endpoint_with_args_test() {
raw_addr: ManagedByteArray::new_from_bytes(b"01020304050607080910"),
},
to: ManagedAddress::from(CROWDFUNDING_ADDRESS.eval_to_array()),
refund_address: ManagedAddress::from(REFUND_ADDRESS.eval_to_array()),
token_id: BRIDGE_TOKEN_ID.into(),
amount: BigUint::from(500u64),
tx_nonce: 1u64,
Expand Down Expand Up @@ -844,7 +854,7 @@ fn bridge_proxy_empty_endpoint_with_args_test() {

test.world
.check_account(BRIDGE_PROXY_ADDRESS)
.check_storage("str:refundTransactions|u32:1", "0x30313032303330343035303630373038303931300000000000000000050063726f7766756e64696e675f5f5f5f5f5f5f5f5f5f5f0000000d4252494447452d3132333435360000000201f4000000000000000101000000110000000000000000009896800100000000")
.check_storage("str:refundTransactions|u32:1", "0x30313032303330343035303630373038303931300000000000000000050063726f7766756e64696e675f5f5f5f5f5f5f5f5f5f5f726566756e645f616464725f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f0000000d4252494447452d3132333435360000000201f4000000000000000101000000110000000000000000009896800100000000")
.check_storage("str:batchId|u32:1", "1")
.check_storage("str:highestTxId", "1")
.check_storage("str:payments|u32:1", "nested:str:BRIDGE-123456|u64:0|biguint:500");
Expand Down
7 changes: 4 additions & 3 deletions bridge-proxy/wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@

// Init: 1
// Upgrade: 1
// Endpoints: 10
// Endpoints: 11
// Async Callback (empty): 1
// Promise callbacks: 1
// Total number of exported functions: 14
// Total number of exported functions: 15

#![no_std]

Expand All @@ -23,7 +23,8 @@ multiversx_sc_wasm_adapter::endpoints! {
upgrade => upgrade
deposit => deposit
execute => execute
refundTransaction => refund_transaction
refundTransactionToEthereum => refund_transaction_to_ethereum
claimBridgedTokensAfterFailedRefund => claim_bridged_tokens_after_failed_refund
getPendingTransactionById => get_pending_transaction_by_id
getPendingTransactions => get_pending_transactions
refundTransactions => refund_transactions
Expand Down
39 changes: 39 additions & 0 deletions common/sc-proxies/src/bridge_proxy_contract_proxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,32 @@ where
.original_result()
}

pub fn refund_transaction_to_ethereum<
Arg0: ProxyArg<usize>,
>(
self,
tx_id: Arg0,
) -> TxTypedCall<Env, From, To, NotPayable, Gas, ()> {
self.wrapped_tx
.payment(NotPayable)
.raw_call("refundTransactionToEthereum")
.argument(&tx_id)
.original_result()
}

pub fn claim_bridged_tokens_after_failed_refund<
Arg0: ProxyArg<usize>,
>(
self,
tx_id: Arg0,
) -> TxTypedCall<Env, From, To, NotPayable, Gas, ()> {
self.wrapped_tx
.payment(NotPayable)
.raw_call("claimBridgedTokensAfterFailedRefund")
.argument(&tx_id)
.original_result()
}

pub fn get_pending_transaction_by_id<
Arg0: ProxyArg<usize>,
>(
Expand All @@ -131,6 +157,19 @@ where
.original_result()
}

pub fn refund_transactions<
Arg0: ProxyArg<usize>,
>(
self,
tx_id: Arg0,
) -> TxTypedCall<Env, From, To, NotPayable, Gas, transaction::EthTransaction<Env::Api>> {
self.wrapped_tx
.payment(NotPayable)
.raw_call("refundTransactions")
.argument(&tx_id)
.original_result()
}

pub fn highest_tx_id(
self,
) -> TxTypedCall<Env, From, To, NotPayable, Gas, usize> {
Expand Down
6 changes: 3 additions & 3 deletions common/sc-proxies/src/multisig_proxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ where
/// Sender Address, Destination Address, Token ID, Amount, Tx Nonce
pub fn propose_multi_transfer_esdt_batch<
Arg0: ProxyArg<u64>,
Arg1: ProxyArg<MultiValueEncoded<Env::Api, MultiValue6<eth_address::EthAddress<Env::Api>, ManagedAddress<Env::Api>, TokenIdentifier<Env::Api>, BigUint<Env::Api>, u64, ManagedOption<Env::Api, ManagedBuffer<Env::Api>>>>>,
Arg1: ProxyArg<MultiValueEncoded<Env::Api, MultiValue7<eth_address::EthAddress<Env::Api>, ManagedAddress<Env::Api>, ManagedAddress<Env::Api>, TokenIdentifier<Env::Api>, BigUint<Env::Api>, u64, ManagedOption<Env::Api, ManagedBuffer<Env::Api>>>>>,
>(
self,
eth_batch_id: Arg0,
Expand Down Expand Up @@ -902,7 +902,7 @@ where
/// To check if it was executed as well, use the wasActionExecuted view
pub fn was_transfer_action_proposed<
Arg0: ProxyArg<u64>,
Arg1: ProxyArg<MultiValueEncoded<Env::Api, MultiValue6<eth_address::EthAddress<Env::Api>, ManagedAddress<Env::Api>, TokenIdentifier<Env::Api>, BigUint<Env::Api>, u64, ManagedOption<Env::Api, ManagedBuffer<Env::Api>>>>>,
Arg1: ProxyArg<MultiValueEncoded<Env::Api, MultiValue7<eth_address::EthAddress<Env::Api>, ManagedAddress<Env::Api>, ManagedAddress<Env::Api>, TokenIdentifier<Env::Api>, BigUint<Env::Api>, u64, ManagedOption<Env::Api, ManagedBuffer<Env::Api>>>>>,
>(
self,
eth_batch_id: Arg0,
Expand All @@ -921,7 +921,7 @@ where
/// Will return 0 if the transfers were not proposed
pub fn get_action_id_for_transfer_batch<
Arg0: ProxyArg<u64>,
Arg1: ProxyArg<MultiValueEncoded<Env::Api, MultiValue6<eth_address::EthAddress<Env::Api>, ManagedAddress<Env::Api>, TokenIdentifier<Env::Api>, BigUint<Env::Api>, u64, ManagedOption<Env::Api, ManagedBuffer<Env::Api>>>>>,
Arg1: ProxyArg<MultiValueEncoded<Env::Api, MultiValue7<eth_address::EthAddress<Env::Api>, ManagedAddress<Env::Api>, ManagedAddress<Env::Api>, TokenIdentifier<Env::Api>, BigUint<Env::Api>, u64, ManagedOption<Env::Api, ManagedBuffer<Env::Api>>>>>,
>(
self,
eth_batch_id: Arg0,
Expand Down
4 changes: 3 additions & 1 deletion common/transaction/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,17 @@ impl<M: ManagedTypeApi> Default for CallData<M> {
pub struct EthTransaction<M: ManagedTypeApi> {
pub from: EthAddress<M>,
pub to: ManagedAddress<M>,
pub refund_address: ManagedAddress<M>,
pub token_id: TokenIdentifier<M>,
pub amount: BigUint<M>,
pub tx_nonce: TxNonce,
pub call_data: ManagedOption<M, ManagedBuffer<M>>,
}

pub type EthTxAsMultiValue<M> = MultiValue6<
pub type EthTxAsMultiValue<M> = MultiValue7<
EthAddress<M>,
ManagedAddress<M>,
ManagedAddress<M>,
TokenIdentifier<M>,
BigUint<M>,
TxNonce,
Expand Down
10 changes: 10 additions & 0 deletions multi-transfer-esdt/tests/multi_transfer_blackbox_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ const USER1_ADDRESS: TestAddress = TestAddress::new("user1");
const USER2_ADDRESS: TestAddress = TestAddress::new("user2");
const RELAYER1_ADDRESS: TestAddress = TestAddress::new("relayer1");
const RELAYER2_ADDRESS: TestAddress = TestAddress::new("relayer2");
const REFUND_ADDRESS: TestAddress = TestAddress::new("refund-addr");

const ESDT_SAFE_ETH_TX_GAS_LIMIT: u64 = 150_000;
const MAX_AMOUNT: u64 = 100_000_000_000_000u64;
Expand Down Expand Up @@ -753,6 +754,7 @@ fn basic_transfer_test() {
raw_addr: ManagedByteArray::default(),
},
to: ManagedAddress::from(USER1_ADDRESS.eval_to_array()),
refund_address: ManagedAddress::from(REFUND_ADDRESS.eval_to_array()),
token_id: TokenIdentifier::from(BRIDGE_TOKEN_ID),
amount: token_amount.clone(),
tx_nonce: 1u64,
Expand Down Expand Up @@ -803,6 +805,7 @@ fn batch_transfer_both_executed_test() {
raw_addr: ManagedByteArray::new_from_bytes(b"01020304050607080910"),
},
to: ManagedAddress::from(USER2_ADDRESS.eval_to_array()),
refund_address: ManagedAddress::from(REFUND_ADDRESS.eval_to_array()),
token_id: TokenIdentifier::from(BRIDGE_TOKEN_ID),
amount: token_amount.clone(),
tx_nonce: 1u64,
Expand All @@ -814,6 +817,7 @@ fn batch_transfer_both_executed_test() {
raw_addr: ManagedByteArray::new_from_bytes(b"01020304050607080910"),
},
to: ManagedAddress::from(USER1_ADDRESS.eval_to_array()),
refund_address: ManagedAddress::from(REFUND_ADDRESS.eval_to_array()),
token_id: TokenIdentifier::from(WRAPPED_TOKEN_ID),
amount: token_amount.clone(),
tx_nonce: 2u64,
Expand Down Expand Up @@ -870,6 +874,7 @@ fn batch_two_transfers_same_token_test() {
raw_addr: ManagedByteArray::new_from_bytes(b"01020304050607080910"),
},
to: ManagedAddress::from(USER2_ADDRESS.eval_to_array()),
refund_address: ManagedAddress::from(REFUND_ADDRESS.eval_to_array()),
token_id: TokenIdentifier::from(BRIDGE_TOKEN_ID),
amount: token_amount.clone(),
tx_nonce: 1u64,
Expand All @@ -881,6 +886,7 @@ fn batch_two_transfers_same_token_test() {
raw_addr: ManagedByteArray::new_from_bytes(b"01020304050607080910"),
},
to: ManagedAddress::from(USER1_ADDRESS.eval_to_array()),
refund_address: ManagedAddress::from(REFUND_ADDRESS.eval_to_array()),
token_id: TokenIdentifier::from(BRIDGE_TOKEN_ID),
amount: token_amount.clone(),
tx_nonce: 2u64,
Expand Down Expand Up @@ -937,6 +943,7 @@ fn batch_transfer_both_failed_test() {
raw_addr: ManagedByteArray::new_from_bytes(b"01020304050607080910"),
},
to: ManagedAddress::from(BRIDGE_PROXY_ADDRESS.eval_to_array()),
refund_address: ManagedAddress::from(REFUND_ADDRESS.eval_to_array()),
token_id: TokenIdentifier::from(BRIDGE_TOKEN_ID),
amount: token_amount.clone(),
tx_nonce: 1u64,
Expand All @@ -948,6 +955,7 @@ fn batch_transfer_both_failed_test() {
raw_addr: ManagedByteArray::new_from_bytes(b"01020304050607080910"),
},
to: ManagedAddress::from(BRIDGE_PROXY_ADDRESS.eval_to_array()),
refund_address: ManagedAddress::from(REFUND_ADDRESS.eval_to_array()),
token_id: TokenIdentifier::from(BRIDGE_TOKEN_ID),
amount: token_amount.clone(),
tx_nonce: 2u64,
Expand Down Expand Up @@ -1235,6 +1243,7 @@ fn add_refund_batch_test_should_work() {
let eth_tx = EthTransaction {
from: EthAddress::zero(),
to: ManagedAddress::from(USER1_ADDRESS.eval_to_array()),
refund_address: ManagedAddress::from(REFUND_ADDRESS.eval_to_array()),
token_id: TokenIdentifier::from(TOKEN_TICKER),
amount: BigUint::from(MAX_AMOUNT),
tx_nonce: 1u64,
Expand Down Expand Up @@ -1307,6 +1316,7 @@ fn batch_transfer_esdt_token_to_address_zero() {
let eth_tx = EthTransaction {
from: EthAddress::zero(),
to: ManagedAddress::zero(),
refund_address: ManagedAddress::from(REFUND_ADDRESS.eval_to_array()),
token_id: TokenIdentifier::from(TOKEN_TICKER),
amount: BigUint::from(MAX_AMOUNT),
tx_nonce: 1u64,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -300,24 +300,28 @@
"0x01",
"0x3564393539653938656137336333353737386666",
"0x65726431647977376179736e306e776d75616876786e68326530706d306b676a",
"0x65726431647977376179736e306e776d75616876786e68326530706d306b676a",
"0x455448555344432d616661363839",
"0x1388",
"0x01",
"0x",
"0x3564393539653938656137336333353737386666",
"0x65726431647977376179736e306e776d75616876786e68326530706d306b676a",
"0x65726431647977376179736e306e776d75616876786e68326530706d306b676a",
"0x455448555344432d616661363839",
"0x1388",
"0x02",
"0x",
"0x3564393539653938656137336333353737386666",
"0x65726431647977376179736e306e776d75616876786e68326530706d306b676a",
"0x65726431647977376179736e306e776d75616876786e68326530706d306b676a",
"0x455448555344432d616661363839",
"0x1388",
"0x03",
"0x01000000110000000466756e640000000005f5e10000",
"0x3564393539653938656137336333353737386666",
"0x65726431647977376179736e306e776d75616876786e68326530706d306b676a",
"0x65726431647977376179736e306e776d75616876786e68326530706d306b676a",
"0x455448555344432d616661363839",
"0x1388",
"0x04",
Expand Down
Loading