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

Add callbacks for get_tokens and move_refund_batch_to_safe #276

Open
wants to merge 4 commits into
base: feat/v3.1
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
136 changes: 78 additions & 58 deletions multi-transfer-esdt/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use transaction::{EthTransaction, PaymentsVec, Transaction, TxNonce};
const DEFAULT_MAX_TX_BATCH_SIZE: usize = 10;
const DEFAULT_MAX_TX_BATCH_BLOCK_DURATION: u64 = 100_000_000u64;
const GAS_LIMIT_ESDT_TRANSFER: u64 = 200_000;
const GAS_LIMIT_GET_TOKENS: u64 = 10_000_000; //TODO: adjust value
const CHAIN_SPECIFIC_TO_UNIVERSAL_TOKEN_MAPPING: &[u8] = b"chainSpecificToUniversalMapping";
const DEFAULT_GAS_LIMIT_FOR_REFUND_CALLBACK: u64 = 4_000_000; // 4 million

Expand Down Expand Up @@ -47,8 +48,6 @@ pub trait MultiTransferEsdt:
batch_id: u64,
transfers: MultiValueEncoded<EthTransaction<Self::Api>>,
) {
let mut valid_payments_list = ManagedVec::new();
let mut valid_tx_list = ManagedVec::new();
let mut refund_tx_list = ManagedVec::new();

let own_sc_address = self.blockchain().get_sc_address();
Expand All @@ -57,27 +56,17 @@ pub trait MultiTransferEsdt:
let safe_address = self.get_esdt_safe_address();

for eth_tx in transfers {
// let token_roles = self
// .blockchain()
// .get_esdt_local_roles(&eth_tx.token_id.clone());
// if token_roles.has_role(&EsdtLocalRole::Transfer) {
// self.add_eth_tx_to_refund_tx_list(eth_tx.clone(), &mut refund_tx_list);
// self.token_with_transfer_role_event(eth_tx.token_id);
// continue;
// }

let is_success: bool = self
.tx()
self.tx()
.to(safe_address.clone())
.typed(esdt_safe_proxy::EsdtSafeProxy)
.get_tokens(&eth_tx.token_id, &eth_tx.amount)
.returns(ReturnsResult)
.sync_call();

if !is_success {
self.add_eth_tx_to_refund_tx_list(eth_tx, &mut refund_tx_list);
continue;
}
.gas(GAS_LIMIT_GET_TOKENS)
.callback(
self.callbacks()
.get_tokens_callback(eth_tx.clone(), batch_id),
)
.with_extra_gas_for_callback(DEFAULT_GAS_LIMIT_FOR_REFUND_CALLBACK)
.register_promise();

let universal_token = self.get_universal_token(eth_tx.clone());

Expand Down Expand Up @@ -118,17 +107,41 @@ pub trait MultiTransferEsdt:
eth_tx.tx_nonce,
);
}

valid_tx_list.push(eth_tx.clone());
valid_payments_list.push(EsdtTokenPayment::new(eth_tx.token_id, 0, eth_tx.amount));
}

let payments_after_wrapping = self.wrap_tokens(valid_payments_list);
self.distribute_payments(valid_tx_list, payments_after_wrapping, batch_id);

self.add_multiple_tx_to_batch(&refund_tx_list);
}

#[promises_callback]
fn get_tokens_callback(
&self,
#[call_result] result: ManagedAsyncCallResult<()>,
eth_tx: EthTransaction<Self::Api>,
batch_id: u64,
) {
match result {
ManagedAsyncCallResult::Ok(()) => {
let payment =
EsdtTokenPayment::new(eth_tx.token_id.clone(), 0, eth_tx.amount.clone());
let payments_after_wrapping =
self.wrap_tokens(PaymentsVec::from_single_item(payment));
self.distribute_payments(
ManagedVec::from_single_item(eth_tx),
payments_after_wrapping,
batch_id,
);

self.get_tokens_esdt_safe_success_event(batch_id);
}
ManagedAsyncCallResult::Err(_) => {
let refund_tx = self.convert_to_refund_tx(eth_tx.clone());
self.add_to_batch(refund_tx);

self.transfer_failed_frozen_destination_account_event(batch_id, eth_tx.tx_nonce);
}
}
}

#[only_owner]
#[endpoint(moveRefundBatchToSafe)]
fn move_refund_batch_to_safe(&self) {
Expand All @@ -144,36 +157,44 @@ pub trait MultiTransferEsdt:
let mut refund_payments = ManagedVec::new();

for tx_fields in all_tx_fields {
let (_, tx_nonce, _, _, token_identifier, amount) =
tx_fields.clone().into_tuple();

if self.is_refund_valid(&token_identifier) {
refund_batch.push(Transaction::from(tx_fields));
refund_payments.push(EsdtTokenPayment::new(token_identifier, 0, amount));
} else {
require!(
self.unprocessed_refund_txs(tx_nonce).is_empty(),
"This transcation is already marked as unprocessed"
);
self.unprocessed_refund_txs(tx_nonce)
.set(Transaction::from(tx_fields));

self.unprocessed_refund_txs_event(tx_nonce);
}
let (_, _, _, _, token_identifier, amount) = tx_fields.clone().into_tuple();

refund_batch.push(Transaction::from(tx_fields));
refund_payments.push(EsdtTokenPayment::new(token_identifier, 0, amount));
}

let esdt_safe_addr = self.get_esdt_safe_address();
self.tx()
.to(esdt_safe_addr)
.typed(esdt_safe_proxy::EsdtSafeProxy)
.add_refund_batch(refund_batch)
.add_refund_batch(refund_batch.clone())
.payment(refund_payments)
.sync_call();
.gas(GAS_LIMIT_GET_TOKENS)
.callback(
self.callbacks()
.move_refund_batch_to_safe_callback(refund_batch),
)
.with_extra_gas_for_callback(DEFAULT_GAS_LIMIT_FOR_REFUND_CALLBACK)
.register_promise();
}
OptionalValue::None => {}
}
}

#[promises_callback]
fn move_refund_batch_to_safe_callback(
&self,
#[call_result] result: ManagedAsyncCallResult<()>,
refund_batch: ManagedVec<Transaction<Self::Api>>,
) {
match result {
ManagedAsyncCallResult::Ok(()) => self.move_refund_batch_to_safe_success_event(),
ManagedAsyncCallResult::Err(_) => {
self.add_multiple_tx_to_batch(&refund_batch);
}
}
}

#[only_owner]
#[endpoint(addUnprocessedRefundTxToBatch)]
fn add_unprocessed_refund_tx_to_batch(&self, tx_id: u64) {
Expand All @@ -196,18 +217,6 @@ pub trait MultiTransferEsdt:
refund_tx_list.push(refund_tx);
}

fn is_refund_valid(&self, token_id: &TokenIdentifier) -> bool {
let esdt_safe_addr = self.get_esdt_safe_address();
let own_sc_address = self.blockchain().get_sc_address();
let sc_shard = self.blockchain().get_shard_of_address(&own_sc_address);

if self.is_account_same_shard_frozen(sc_shard, &esdt_safe_addr, token_id) {
return false;
}

return true;
}

fn get_universal_token(&self, eth_tx: EthTransaction<Self::Api>) -> TokenIdentifier {
let mut storage_key = StorageKey::new(CHAIN_SPECIFIC_TO_UNIVERSAL_TOKEN_MAPPING);
storage_key.append_item(&eth_tx.token_id);
Expand Down Expand Up @@ -319,15 +328,20 @@ pub trait MultiTransferEsdt:
.to(&eth_tx.to)
.single_esdt(&p.token_identifier, 0, &p.amount)
.gas(GAS_LIMIT_ESDT_TRANSFER)
.callback(self.callbacks().transfer_callback(eth_tx.clone(), batch_id))
.callback(
self.callbacks()
.distribute_payments_callback(eth_tx.clone(), batch_id),
)
.with_extra_gas_for_callback(DEFAULT_GAS_LIMIT_FOR_REFUND_CALLBACK)
.register_promise();
}
}
}

// callbacks

#[promises_callback]
fn transfer_callback(
fn distribute_payments_callback(
&self,
#[call_result] result: ManagedAsyncCallResult<()>,
tx: EthTransaction<Self::Api>,
Expand Down Expand Up @@ -392,6 +406,12 @@ pub trait MultiTransferEsdt:
#[indexed] tx_id: u64,
);

#[event("getTokensEsdtEsdtSuccess")]
fn get_tokens_esdt_safe_success_event(&self, #[indexed] batch_id: u64);

#[event("moveRefundBatchToSafeSuccess")]
fn move_refund_batch_to_safe_success_event(&self);

#[event("tokenWithTransferRole")]
fn token_with_transfer_role_event(&self, #[indexed] token_id: TokenIdentifier);

Expand Down
67 changes: 67 additions & 0 deletions multi-transfer-esdt/tests/multi_transfer_blackbox_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1535,3 +1535,70 @@ fn multi_transfer_reduce_max_tx_batch_size_test() {
"Incorrect batch status"
);
}

// Add back test when EsdtLocalRole::Transfer is introduced back in the framework
// #[test]
// fn transfer_role_token_test() {
// let mut state = MultiTransferTestState::new();
// let token_amount = BigUint::from(500u64);
// let bridge_token_id = TokenIdentifier::from(BRIDGE_TOKEN_ID);

// state.world.start_trace();

// state.deploy_contracts();
// state.config_multi_transfer();

// state
// .world
// .tx()
// .from(OWNER_ADDRESS)
// .to(ESDTSystemSCAddress)
// .gas(100_000_000u64)
// .typed(ESDTSystemSCProxy)
// .set_special_roles(
// ESDT_SAFE_ADDRESS,
// bridge_token_id.clone(),
// [EsdtLocalRole::Transfer][..].iter().cloned(),
// )
// .run();

// let call_data = ManagedBuffer::from(b"add");
// call_data
// .clone()
// .concat(ManagedBuffer::from(GAS_LIMIT.to_string()));
// call_data.clone().concat(ManagedBuffer::default());

// let eth_tx = EthTransaction {
// from: EthAddress {
// raw_addr: ManagedByteArray::default(),
// },
// to: ManagedAddress::from(USER1_ADDRESS.eval_to_array()),
// token_id: bridge_token_id,
// amount: token_amount.clone(),
// tx_nonce: 1u64,
// call_data: ManagedOption::some(call_data),
// };

// let mut transfers: MultiValueEncoded<StaticApi, EthTransaction<StaticApi>> =
// MultiValueEncoded::new();
// transfers.push(eth_tx);

// state
// .world
// .tx()
// .from(MULTISIG_ADDRESS)
// .to(MULTI_TRANSFER_ADDRESS)
// .typed(multi_transfer_esdt_proxy::MultiTransferEsdtProxy)
// .batch_transfer_esdt_token(1u32, transfers)
// .run();

// // no tokens for user
// state
// .world
// .check_account(USER1_ADDRESS)
// .esdt_balance(BRIDGE_TOKEN_ID, 0);

// state
// .world
// .write_scenario_trace("scenarios/transfer_role_token_test.scen.json");
// }
8 changes: 5 additions & 3 deletions multi-transfer-esdt/wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
// Upgrade: 1
// Endpoints: 13
// Async Callback (empty): 1
// Promise callbacks: 1
// Total number of exported functions: 17
// Promise callbacks: 3
// Total number of exported functions: 19

#![no_std]

Expand All @@ -34,7 +34,9 @@ multiversx_sc_wasm_adapter::endpoints! {
getLastBatchId => last_batch_id
setMaxBridgedAmount => set_max_bridged_amount
getMaxBridgedAmount => max_bridged_amount
transfer_callback => transfer_callback
get_tokens_callback => get_tokens_callback
move_refund_batch_to_safe_callback => move_refund_batch_to_safe_callback
distribute_payments_callback => distribute_payments_callback
)
}

Expand Down
Loading