From 2f1b424b3369103f868b85fcb1b3991da27d00b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Costin=20Caraba=C8=99?= Date: Mon, 2 Dec 2024 13:37:27 +0200 Subject: [PATCH] esdt-safe: create_transaction add min_bridge_amount --- bridge-proxy/src/bridge-proxy.rs | 2 +- bridged-tokens-wrapper/src/lib.rs | 11 +- .../bridged_tokens_wrapper_whitebox_test.rs | 4 + .../mock-esdt-safe/src/mock_esdt_safe.rs | 4 +- .../mock-esdt-safe/wasm/src/lib.rs | 2 +- .../src/bridged_tokens_wrapper_proxy.rs | 3 + common/sc-proxies/src/esdt_safe_proxy.rs | 28 +++- common/sc-proxies/src/multisig_proxy.rs | 13 ++ esdt-safe/src/lib.rs | 131 ++++++++++-------- esdt-safe/tests/esdt_safe_blackbox_test.rs | 18 +-- esdt-safe/wasm/src/lib.rs | 7 +- .../tests/multi_transfer_blackbox_test.rs | 9 +- multisig/wasm/src/lib.rs | 5 +- 13 files changed, 147 insertions(+), 90 deletions(-) diff --git a/bridge-proxy/src/bridge-proxy.rs b/bridge-proxy/src/bridge-proxy.rs index f66581d4..de96deb5 100644 --- a/bridge-proxy/src/bridge-proxy.rs +++ b/bridge-proxy/src/bridge-proxy.rs @@ -136,7 +136,7 @@ pub trait BridgeProxyContract: self.tx() .to(esdt_safe_contract_address) .typed(esdt_safe_proxy::EsdtSafeProxy) - .create_transaction( + .create_refund_transaction( tx.from, OptionalValue::Some(esdt_safe_proxy::RefundInfo { address: tx.to, diff --git a/bridged-tokens-wrapper/src/lib.rs b/bridged-tokens-wrapper/src/lib.rs index 73428a24..4bca2d4b 100644 --- a/bridged-tokens-wrapper/src/lib.rs +++ b/bridged-tokens-wrapper/src/lib.rs @@ -261,21 +261,14 @@ pub trait BridgedTokensWrapper: requested_token: TokenIdentifier, safe_address: ManagedAddress, to: EthAddress, + opt_min_bridge_amount: OptionalValue>, ) { let converted_amount = self.unwrap_token_common(&requested_token); - let caller = self.blockchain().get_caller(); self.tx() .to(safe_address) .typed(esdt_safe_proxy::EsdtSafeProxy) - .create_transaction( - to, - OptionalValue::Some(esdt_safe_proxy::RefundInfo { - address: caller, - initial_batch_id: 0, - initial_nonce: 0, - }), - ) + .create_transaction(to, opt_min_bridge_amount) .single_esdt(&requested_token, 0, &converted_amount) .sync_call(); } diff --git a/bridged-tokens-wrapper/tests/bridged_tokens_wrapper_whitebox_test.rs b/bridged-tokens-wrapper/tests/bridged_tokens_wrapper_whitebox_test.rs index a462f098..214d0588 100644 --- a/bridged-tokens-wrapper/tests/bridged_tokens_wrapper_whitebox_test.rs +++ b/bridged-tokens-wrapper/tests/bridged_tokens_wrapper_whitebox_test.rs @@ -396,6 +396,7 @@ fn test_unwrap_token_create_transaction_should_fail_case_1() { managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER), ManagedAddress::new_from_bytes(b"0102030405060708090a0b0c0d0e0f10"), address, + OptionalValue::None, ); }, |r| r.assert_user_error("Contract is paused"), @@ -434,6 +435,7 @@ fn test_unwrap_token_create_transaction_should_fail_case_2() { managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER), ManagedAddress::new_from_bytes(b"0102030405060708090a0b0c0d0e0f10"), address, + OptionalValue::None, ); }, |r| r.assert_user_error("Must pay more than 0 tokens!"), @@ -472,6 +474,7 @@ fn test_unwrap_token_create_transaction_should_fail_case_3() { managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER), ManagedAddress::zero(), address, + OptionalValue::None, ); }, |r| r.assert_user_error("Esdt token unavailable"), @@ -546,6 +549,7 @@ fn test_unwrap_token_create_transaction_should_fail_case_4() { managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER), ManagedAddress::zero(), address, + OptionalValue::None, ); }, |r| r.assert_user_error("Contract does not have enough funds"), diff --git a/common/mock-contracts/mock-esdt-safe/src/mock_esdt_safe.rs b/common/mock-contracts/mock-esdt-safe/src/mock_esdt_safe.rs index 991fc205..99718817 100644 --- a/common/mock-contracts/mock-esdt-safe/src/mock_esdt_safe.rs +++ b/common/mock-contracts/mock-esdt-safe/src/mock_esdt_safe.rs @@ -28,8 +28,8 @@ pub trait MockEsdtSafe { fn upgrade(&self) {} #[payable("*")] - #[endpoint(createTransaction)] - fn create_transaction( + #[endpoint(createRefundTransaction)] + fn create_refund_transaction( &self, _to: EthAddress, _opt_refund_info: OptionalValue>, diff --git a/common/mock-contracts/mock-esdt-safe/wasm/src/lib.rs b/common/mock-contracts/mock-esdt-safe/wasm/src/lib.rs index 7c9a8414..5f7aed31 100644 --- a/common/mock-contracts/mock-esdt-safe/wasm/src/lib.rs +++ b/common/mock-contracts/mock-esdt-safe/wasm/src/lib.rs @@ -20,7 +20,7 @@ multiversx_sc_wasm_adapter::endpoints! { ( init => init upgrade => upgrade - createTransaction => create_transaction + createRefundTransaction => create_refund_transaction ) } diff --git a/common/sc-proxies/src/bridged_tokens_wrapper_proxy.rs b/common/sc-proxies/src/bridged_tokens_wrapper_proxy.rs index 07b3185d..0610fc9b 100644 --- a/common/sc-proxies/src/bridged_tokens_wrapper_proxy.rs +++ b/common/sc-proxies/src/bridged_tokens_wrapper_proxy.rs @@ -191,17 +191,20 @@ where Arg0: ProxyArg>, Arg1: ProxyArg>, Arg2: ProxyArg>, + Arg3: ProxyArg>>, >( self, requested_token: Arg0, safe_address: Arg1, to: Arg2, + opt_min_bridge_amount: Arg3, ) -> TxTypedCall { self.wrapped_tx .raw_call("unwrapTokenCreateTransaction") .argument(&requested_token) .argument(&safe_address) .argument(&to) + .argument(&opt_min_bridge_amount) .original_result() } diff --git a/common/sc-proxies/src/esdt_safe_proxy.rs b/common/sc-proxies/src/esdt_safe_proxy.rs index 3501f54b..7759087a 100644 --- a/common/sc-proxies/src/esdt_safe_proxy.rs +++ b/common/sc-proxies/src/esdt_safe_proxy.rs @@ -139,6 +139,28 @@ where /// /// fee_amount = price_per_gas_unit * eth_tx_gas_limit pub fn create_transaction< + Arg0: ProxyArg>, + Arg1: ProxyArg>>, + >( + self, + to: Arg0, + opt_min_bridge_amount: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("createTransaction") + .argument(&to) + .argument(&opt_min_bridge_amount) + .original_result() + } + + /// Create an Ethereum -> MultiversX refund transaction. Only fungible tokens are accepted. + /// + /// Every transfer will have a part of the tokens subtracted as fees. + /// The fee amount depends on the global eth_tx_gas_limit + /// and the current GWEI price, respective to the bridged token + /// + /// fee_amount = price_per_gas_unit * eth_tx_gas_limit + pub fn create_refund_transaction< Arg0: ProxyArg>, Arg1: ProxyArg>>, >( @@ -147,13 +169,13 @@ where opt_refund_info: Arg1, ) -> TxTypedCall { self.wrapped_tx - .raw_call("createTransaction") + .raw_call("createRefundTransaction") .argument(&to) .argument(&opt_refund_info) .original_result() } - pub fn create_transaction_sc_call< + pub fn create_refund_transaction_sc_call< Arg0: ProxyArg>, Arg1: ProxyArg>, Arg2: ProxyArg>>, @@ -164,7 +186,7 @@ where opt_refund_info: Arg2, ) -> TxTypedCall { self.wrapped_tx - .raw_call("createTransactionSCCall") + .raw_call("createRefundTransactionSCCall") .argument(&to) .argument(&data) .argument(&opt_refund_info) diff --git a/common/sc-proxies/src/multisig_proxy.rs b/common/sc-proxies/src/multisig_proxy.rs index 8a92e992..f3e21fdf 100644 --- a/common/sc-proxies/src/multisig_proxy.rs +++ b/common/sc-proxies/src/multisig_proxy.rs @@ -298,6 +298,19 @@ where .original_result() } + pub fn clear_actions_for_batch_id< + Arg0: ProxyArg, + >( + self, + eth_batch_id: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("clearActionsForBatchId") + .argument(ð_batch_id) + .original_result() + } + /// Used by board members to sign actions. pub fn sign< Arg0: ProxyArg, diff --git a/esdt-safe/src/lib.rs b/esdt-safe/src/lib.rs index 8c36da72..2d31003c 100644 --- a/esdt-safe/src/lib.rs +++ b/esdt-safe/src/lib.rs @@ -253,6 +253,7 @@ pub trait EsdtSafe: fn create_transaction_common( &self, to: EthAddress, + min_bridge_amount: BigUint, opt_refund_info: OptionalValue>, ) -> TransactionDetails { require!(self.not_paused(), "Cannot create transaction while paused"); @@ -266,6 +267,13 @@ pub trait EsdtSafe: "Transaction fees cost more than the entire bridged amount" ); + if min_bridge_amount != BigUint::zero() { + require!( + required_fee < min_bridge_amount, + "Minimum bridged amount after fee is not achieved" + ); + } + self.require_below_max_amount(&payment_token, &payment_amount); // This addr is used for the refund, if the transaction fails @@ -350,76 +358,83 @@ pub trait EsdtSafe: #[payable("*")] #[endpoint(createTransaction)] fn create_transaction( + &self, + to: EthAddress, + opt_min_bridge_amount: OptionalValue>, + ) { + let transaction_details = match opt_min_bridge_amount { + OptionalValue::Some(min_bridge_amount) => { + self.create_transaction_common(to, min_bridge_amount, OptionalValue::None) + } + OptionalValue::None => { + self.create_transaction_common(to, BigUint::zero(), OptionalValue::None) + } + }; + // let transaction_details = self.create_transaction_common(to, opt_refund_info); + self.create_transaction_event( + transaction_details.batch_id, + transaction_details.tx_nonce, + transaction_details.payment_token, + transaction_details.actual_bridged_amount, + transaction_details.required_fee, + transaction_details + .refund_info + .address + .as_managed_buffer() + .clone(), + transaction_details.to_address, + ); + } + + /// Create an Ethereum -> MultiversX refund transaction. Only fungible tokens are accepted. + /// + /// Every transfer will have a part of the tokens subtracted as fees. + /// The fee amount depends on the global eth_tx_gas_limit + /// and the current GWEI price, respective to the bridged token + /// + /// fee_amount = price_per_gas_unit * eth_tx_gas_limit + #[payable("*")] + #[endpoint(createRefundTransaction)] + fn create_refund_transaction( &self, to: EthAddress, opt_refund_info: OptionalValue>, ) { - let transaction_details = self.create_transaction_common(to, opt_refund_info); - - if !transaction_details.is_refund_tx { - self.create_transaction_event( - transaction_details.batch_id, - transaction_details.tx_nonce, - transaction_details.payment_token, - transaction_details.actual_bridged_amount, - transaction_details.required_fee, - transaction_details - .refund_info - .address - .as_managed_buffer() - .clone(), - transaction_details.to_address, - ); - } else { - self.create_refund_transaction_event( - transaction_details.batch_id, - transaction_details.tx_nonce, - transaction_details.payment_token, - transaction_details.actual_bridged_amount, - transaction_details.required_fee, - transaction_details.refund_info.initial_batch_id, - transaction_details.refund_info.initial_nonce, - ); - } + let transaction_details = + self.create_transaction_common(to, BigUint::zero(), opt_refund_info); + + self.create_refund_transaction_event( + transaction_details.batch_id, + transaction_details.tx_nonce, + transaction_details.payment_token, + transaction_details.actual_bridged_amount, + transaction_details.required_fee, + transaction_details.refund_info.initial_batch_id, + transaction_details.refund_info.initial_nonce, + ); } #[payable("*")] - #[endpoint(createTransactionSCCall)] - fn create_transaction_sc_call( + #[endpoint(createRefundTransactionSCCall)] + fn create_refund_transaction_sc_call( &self, to: EthAddress, data: ManagedBuffer, opt_refund_info: OptionalValue>, ) { - let transaction_details = self.create_transaction_common(to, opt_refund_info); - - if !transaction_details.is_refund_tx { - self.create_transaction_sc_call_event( - transaction_details.batch_id, - transaction_details.tx_nonce, - transaction_details.payment_token, - transaction_details.actual_bridged_amount, - transaction_details.required_fee, - transaction_details - .refund_info - .address - .as_managed_buffer() - .clone(), - transaction_details.to_address, - data, - ); - } else { - self.create_refund_transaction_sc_call_event( - transaction_details.batch_id, - transaction_details.tx_nonce, - transaction_details.payment_token, - transaction_details.actual_bridged_amount, - transaction_details.required_fee, - transaction_details.refund_info.initial_batch_id, - transaction_details.refund_info.initial_nonce, - data, - ); - } + let transaction_details = + self.create_transaction_common(to, BigUint::zero(), opt_refund_info); + + self.create_refund_transaction_sc_call_event( + transaction_details.batch_id, + transaction_details.tx_nonce, + transaction_details.payment_token, + transaction_details.actual_bridged_amount, + transaction_details.required_fee, + transaction_details.refund_info.initial_batch_id, + transaction_details.refund_info.initial_nonce, + data, + ); } /// Claim funds for failed MultiversX -> Ethereum transactions. diff --git a/esdt-safe/tests/esdt_safe_blackbox_test.rs b/esdt-safe/tests/esdt_safe_blackbox_test.rs index 2e69849b..8c2a8f63 100644 --- a/esdt-safe/tests/esdt_safe_blackbox_test.rs +++ b/esdt-safe/tests/esdt_safe_blackbox_test.rs @@ -348,7 +348,7 @@ impl EsdtSafeTestState { self.esdt_raw_transaction() .create_transaction( EthAddress::zero(), - OptionalValue::None::>, + OptionalValue::>::None, ) .egld_or_single_esdt( &EgldOrEsdtTokenIdentifier::esdt(token_id), @@ -363,7 +363,7 @@ impl EsdtSafeTestState { self.esdt_raw_transaction() .create_transaction( EthAddress::zero(), - OptionalValue::None::>, + OptionalValue::>::None, ) .egld_or_single_esdt( &EgldOrEsdtTokenIdentifier::esdt(token_id), @@ -736,7 +736,7 @@ fn esdt_safe_create_transaction() { .from(BRIDGE_PROXY_ADDRESS) .to(ESDT_SAFE_ADDRESS) .typed(esdt_safe_proxy::EsdtSafeProxy) - .create_transaction(EthAddress::zero(), OptionalValue::Some(refund_info.clone())) + .create_refund_transaction(EthAddress::zero(), OptionalValue::Some(refund_info.clone())) .single_esdt(&TOKEN_ID.into(), 0, &BigUint::from(10u64)) .run(); @@ -746,7 +746,7 @@ fn esdt_safe_create_transaction() { .from(OWNER_ADDRESS) .to(ESDT_SAFE_ADDRESS) .typed(esdt_safe_proxy::EsdtSafeProxy) - .create_transaction(EthAddress::zero(), OptionalValue::Some(refund_info.clone())) + .create_refund_transaction(EthAddress::zero(), OptionalValue::Some(refund_info.clone())) .single_esdt(&TOKEN_ID.into(), 0, &BigUint::from(10u64)) .returns(ExpectError( ERROR, @@ -760,7 +760,7 @@ fn esdt_safe_create_transaction() { .from(BRIDGED_TOKENS_WRAPPER_ADDRESS) .to(ESDT_SAFE_ADDRESS) .typed(esdt_safe_proxy::EsdtSafeProxy) - .create_transaction(EthAddress::zero(), OptionalValue::Some(refund_info.clone())) + .create_refund_transaction(EthAddress::zero(), OptionalValue::Some(refund_info.clone())) .single_esdt(&TOKEN_ID.into(), 0, &BigUint::from(10u64)) .run(); @@ -810,7 +810,7 @@ fn esdt_safe_create_transaction() { } #[test] -fn esdt_create_transaction_sc_call_test() { +fn esdt_create_refund_transaction_sc_call_test() { let mut state = EsdtSafeTestState::new(); state.multisig_deploy(); state.safe_deploy(); @@ -837,7 +837,7 @@ fn esdt_create_transaction_sc_call_test() { .from(BRIDGE_PROXY_ADDRESS) .to(ESDT_SAFE_ADDRESS) .typed(esdt_safe_proxy::EsdtSafeProxy) - .create_transaction_sc_call( + .create_refund_transaction_sc_call( EthAddress::zero(), data.clone(), OptionalValue::Some(refund_info.clone()), @@ -852,7 +852,7 @@ fn esdt_create_transaction_sc_call_test() { .from(MULTISIG_ADDRESS) .to(ESDT_SAFE_ADDRESS) .typed(esdt_safe_proxy::EsdtSafeProxy) - .create_transaction_sc_call( + .create_refund_transaction_sc_call( EthAddress::zero(), data.clone(), OptionalValue::None::>, @@ -1316,7 +1316,7 @@ fn withdraw_transaction_fees_test() { .typed(esdt_safe_proxy::EsdtSafeProxy) .create_transaction( EthAddress::zero(), - OptionalValue::None::>, + OptionalValue::>::None, ) .single_esdt(&TOKEN_ID.into(), 0, &BigUint::from(1_000_000u64)) .returns(ReturnsResult) diff --git a/esdt-safe/wasm/src/lib.rs b/esdt-safe/wasm/src/lib.rs index 3f1f6eaa..515a7c9e 100644 --- a/esdt-safe/wasm/src/lib.rs +++ b/esdt-safe/wasm/src/lib.rs @@ -6,9 +6,9 @@ // Init: 1 // Upgrade: 1 -// Endpoints: 45 +// Endpoints: 46 // Async Callback (empty): 1 -// Total number of exported functions: 48 +// Total number of exported functions: 49 #![no_std] @@ -23,7 +23,8 @@ multiversx_sc_wasm_adapter::endpoints! { setTransactionBatchStatus => set_transaction_batch_status addRefundBatch => add_refund_batch createTransaction => create_transaction - createTransactionSCCall => create_transaction_sc_call + createRefundTransaction => create_refund_transaction + createRefundTransactionSCCall => create_refund_transaction_sc_call claimRefund => claim_refund withdrawRefundFeesForEthereum => withdraw_refund_fees_for_ethereum withdrawTransactionFees => withdraw_transaction_fees diff --git a/multi-transfer-esdt/tests/multi_transfer_blackbox_test.rs b/multi-transfer-esdt/tests/multi_transfer_blackbox_test.rs index 3d5d822b..2322745c 100644 --- a/multi-transfer-esdt/tests/multi_transfer_blackbox_test.rs +++ b/multi-transfer-esdt/tests/multi_transfer_blackbox_test.rs @@ -606,7 +606,7 @@ impl MultiTransferTestState { self.esdt_raw_transaction() .create_transaction( EthAddress::zero(), - OptionalValue::None::>, + OptionalValue::>::None, ) .egld_or_single_esdt( &EgldOrEsdtTokenIdentifier::esdt(token_id), @@ -621,7 +621,7 @@ impl MultiTransferTestState { self.esdt_raw_transaction() .create_transaction( EthAddress::zero(), - OptionalValue::None::>, + OptionalValue::>::None, ) .egld_or_single_esdt( &EgldOrEsdtTokenIdentifier::esdt(token_id), @@ -1018,6 +1018,7 @@ fn test_unwrap_token_create_transaction_paused() { TokenIdentifier::from(UNIVERSAL_TOKEN_IDENTIFIER), ESDT_SAFE_ADDRESS.to_address(), EthAddress::zero(), + OptionalValue::>::None, ) .egld_or_single_esdt( &EgldOrEsdtTokenIdentifier::esdt(UNIVERSAL_TOKEN_IDENTIFIER), @@ -1072,6 +1073,7 @@ fn test_unwrap_token_create_transaction_insufficient_liquidity() { WRAPPED_TOKEN_ID, ESDT_SAFE_ADDRESS.to_address(), EthAddress::zero(), + OptionalValue::>::None, ) .egld_or_single_esdt( &EgldOrEsdtTokenIdentifier::esdt(UNIVERSAL_TOKEN_IDENTIFIER), @@ -1135,6 +1137,7 @@ fn test_unwrap_token_create_transaction_should_work() { WRAPPED_TOKEN_ID, ESDT_SAFE_ADDRESS.to_address(), EthAddress::zero(), + OptionalValue::>::None, ) .egld_or_single_esdt( &EgldOrEsdtTokenIdentifier::esdt(UNIVERSAL_TOKEN_IDENTIFIER), @@ -1183,6 +1186,7 @@ fn test_unwrap_token_create_transaction_should_fail() { WRAPPED_TOKEN_ID, ESDT_SAFE_ADDRESS.to_address(), EthAddress::zero(), + OptionalValue::>::None, ) .egld_or_single_esdt( &EgldOrEsdtTokenIdentifier::esdt(TOKEN_TICKER), @@ -1211,6 +1215,7 @@ fn test_unwrap_token_create_transaction_amount_zero() { TokenIdentifier::from(WRAPPED_TOKEN_ID), ESDT_SAFE_ADDRESS.to_address(), EthAddress::zero(), + OptionalValue::>::None, ) .egld_or_single_esdt( &EgldOrEsdtTokenIdentifier::esdt(UNIVERSAL_TOKEN_IDENTIFIER), diff --git a/multisig/wasm/src/lib.rs b/multisig/wasm/src/lib.rs index dba3a844..45ec811e 100644 --- a/multisig/wasm/src/lib.rs +++ b/multisig/wasm/src/lib.rs @@ -6,9 +6,9 @@ // Init: 1 // Upgrade: 1 -// Endpoints: 72 +// Endpoints: 73 // Async Callback (empty): 1 -// Total number of exported functions: 75 +// Total number of exported functions: 76 #![no_std] @@ -32,6 +32,7 @@ multiversx_sc_wasm_adapter::endpoints! { withdrawTransactionFees => withdraw_transaction_fees withdrawSlashedAmount => withdraw_slashed_amount performAction => perform_action_endpoint + clearActionsForBatchId => clear_actions_for_batch_id sign => sign upgradeChildContractFromSource => upgrade_child_contract_from_source addBoardMember => add_board_member_endpoint