From cb5a8737ee1463c0bba508e74306775063076bfb Mon Sep 17 00:00:00 2001 From: Alin Cruceat Date: Tue, 19 Sep 2023 08:51:50 +0300 Subject: [PATCH] separate fee and fund endpoints --- .../scenarios/withdraw-egld.scen.json | 2 +- .../examples/digital-cash/src/constants.rs | 5 + .../examples/digital-cash/src/digital_cash.rs | 114 +----------------- .../digital-cash/src/pay_fee_and_fund.rs | 95 +++++++++++++++ .../examples/digital-cash/src/storage.rs | 20 +++ 5 files changed, 126 insertions(+), 110 deletions(-) create mode 100644 contracts/examples/digital-cash/src/constants.rs create mode 100644 contracts/examples/digital-cash/src/pay_fee_and_fund.rs create mode 100644 contracts/examples/digital-cash/src/storage.rs diff --git a/contracts/examples/digital-cash/scenarios/withdraw-egld.scen.json b/contracts/examples/digital-cash/scenarios/withdraw-egld.scen.json index 8da19ef2da..84b6c9a123 100644 --- a/contracts/examples/digital-cash/scenarios/withdraw-egld.scen.json +++ b/contracts/examples/digital-cash/scenarios/withdraw-egld.scen.json @@ -227,7 +227,7 @@ "address:digital_cash_owner_address": { "nonce": "1", "balance": "0", - "storage": "*" + "storage": {} } } } diff --git a/contracts/examples/digital-cash/src/constants.rs b/contracts/examples/digital-cash/src/constants.rs new file mode 100644 index 0000000000..df563263de --- /dev/null +++ b/contracts/examples/digital-cash/src/constants.rs @@ -0,0 +1,5 @@ +pub static NON_EXISTENT_KEY_ERR_MSG: &[u8] = b"non-existent key"; +pub static FEES_NOT_COVERED_ERR_MSG: &[u8] = b"fees not covered"; +pub static CANNOT_DEPOSIT_FUNDS_ERR_MSG: &[u8] = + b"cannot deposit funds without covering the fee cost first"; +pub const SECONDS_PER_ROUND: u64 = 6; diff --git a/contracts/examples/digital-cash/src/digital_cash.rs b/contracts/examples/digital-cash/src/digital_cash.rs index ef713aa923..7bf644ad1e 100644 --- a/contracts/examples/digital-cash/src/digital_cash.rs +++ b/contracts/examples/digital-cash/src/digital_cash.rs @@ -4,63 +4,23 @@ multiversx_sc::imports!(); multiversx_sc::derive_imports!(); +mod constants; mod deposit_info; +mod pay_fee_and_fund; +mod storage; -use deposit_info::{DepositInfo, Fee}; +use constants::*; -pub const SECONDS_PER_ROUND: u64 = 6; pub use multiversx_sc::api::{ED25519_KEY_BYTE_LEN, ED25519_SIGNATURE_BYTE_LEN}; -static NON_EXISTENT_KEY_ERR_MSG: &[u8] = b"non-existent key"; -static FEES_NOT_COVERED_ERR_MSG: &[u8] = b"fees not covered"; -static CANNOT_DEPOSIT_FUNDS_ERR_MSG: &[u8] = - b"cannot deposit funds without covering the fee cost first"; - #[multiversx_sc::contract] -pub trait DigitalCash { +pub trait DigitalCash: pay_fee_and_fund::PayFeeAndFund + storage::StorageModule { #[init] fn init(&self, fee: BigUint, token: EgldOrEsdtTokenIdentifier) { self.fee().set(fee); self.fee_token().set(token); } - // endpoints - - #[endpoint] - #[payable("*")] - fn fund(&self, address: ManagedAddress, valability: u64) { - let deposit_mapper = self.deposit(&address); - require!(!deposit_mapper.is_empty(), FEES_NOT_COVERED_ERR_MSG); - let depositor = deposit_mapper.get().depositor_address; - require!( - self.blockchain().get_caller() == depositor, - "invalid depositor" - ); - - let egld_payment = self.call_value().egld_value().clone_value(); - let esdt_payment = self.call_value().all_esdt_transfers().clone_value(); - let num_tokens = self.get_num_token_transfers(&egld_payment, &esdt_payment); - require!(num_tokens > 0, "amount must be greater than 0"); - - let fee = self.fee().get(); - deposit_mapper.update(|deposit| { - require!( - deposit.egld_funds == 0 && deposit.esdt_funds.is_empty(), - "key already used" - ); - require!( - fee * num_tokens as u64 <= deposit.fees.value, - CANNOT_DEPOSIT_FUNDS_ERR_MSG - ); - - deposit.fees.num_token_to_transfer += num_tokens; - deposit.valability = valability; - deposit.expiration_round = self.get_expiration_round(valability); - deposit.esdt_funds = esdt_payment; - deposit.egld_funds = egld_payment; - }); - } - #[endpoint] fn withdraw(&self, address: ManagedAddress) { let deposit_mapper = self.deposit(&address); @@ -145,37 +105,6 @@ pub trait DigitalCash { self.send_fee_to_address(&fees, &caller_address); } - #[endpoint(depositFees)] - #[payable("EGLD")] - fn deposit_fees(&self, address: ManagedAddress) { - let payment = self.call_value().egld_or_single_esdt(); - let accepted_fee_token = self.fee_token().get(); - require!( - payment.token_identifier == accepted_fee_token, - "Invalid fee token provided" - ); - let caller_address = self.blockchain().get_caller(); - let deposit_mapper = self.deposit(&address); - if !deposit_mapper.is_empty() { - deposit_mapper.update(|deposit| deposit.fees.value += payment.amount); - - return; - } - - let new_deposit = DepositInfo { - depositor_address: caller_address, - esdt_funds: ManagedVec::new(), - egld_funds: BigUint::zero(), - valability: 0, - expiration_round: 0, - fees: Fee { - num_token_to_transfer: 0, - value: payment.amount, - }, - }; - deposit_mapper.set(new_deposit); - } - #[endpoint] fn forward( &self, @@ -260,26 +189,6 @@ pub trait DigitalCash { BigUint::zero() } - // private functions - - fn get_expiration_round(&self, valability: u64) -> u64 { - let valability_rounds = valability / SECONDS_PER_ROUND; - self.blockchain().get_block_round() + valability_rounds - } - - fn get_num_token_transfers( - &self, - egld_value: &BigUint, - esdt_transfers: &ManagedVec, - ) -> usize { - let mut amount = esdt_transfers.len(); - if egld_value > &0 { - amount += 1; - } - - amount - } - fn require_signature( &self, address: &ManagedAddress, @@ -293,17 +202,4 @@ pub trait DigitalCash { } // storage - - #[view] - #[storage_mapper("deposit")] - fn deposit(&self, donor: &ManagedAddress) -> SingleValueMapper>; - - #[storage_mapper("fee")] - fn fee(&self) -> SingleValueMapper; - - #[storage_mapper("feeToken")] - fn fee_token(&self) -> SingleValueMapper; - - #[storage_mapper("collectedFees")] - fn collected_fees(&self) -> SingleValueMapper; } diff --git a/contracts/examples/digital-cash/src/pay_fee_and_fund.rs b/contracts/examples/digital-cash/src/pay_fee_and_fund.rs new file mode 100644 index 0000000000..3e760a6596 --- /dev/null +++ b/contracts/examples/digital-cash/src/pay_fee_and_fund.rs @@ -0,0 +1,95 @@ +multiversx_sc::imports!(); +multiversx_sc::derive_imports!(); + +use crate::{ + constants::*, + deposit_info::{DepositInfo, Fee}, + storage, +}; + +#[multiversx_sc::module] +pub trait PayFeeAndFund: storage::StorageModule { + #[endpoint] + #[payable("*")] + fn fund(&self, address: ManagedAddress, valability: u64) { + let deposit_mapper = self.deposit(&address); + require!(!deposit_mapper.is_empty(), FEES_NOT_COVERED_ERR_MSG); + let depositor = deposit_mapper.get().depositor_address; + require!( + self.blockchain().get_caller() == depositor, + "invalid depositor" + ); + + let egld_payment = self.call_value().egld_value().clone_value(); + let esdt_payment = self.call_value().all_esdt_transfers().clone_value(); + let num_tokens = self.get_num_token_transfers(&egld_payment, &esdt_payment); + require!(num_tokens > 0, "amount must be greater than 0"); + + let fee = self.fee().get(); + deposit_mapper.update(|deposit| { + require!( + deposit.egld_funds == 0 && deposit.esdt_funds.is_empty(), + "key already used" + ); + require!( + fee * num_tokens as u64 <= deposit.fees.value, + CANNOT_DEPOSIT_FUNDS_ERR_MSG + ); + + deposit.fees.num_token_to_transfer += num_tokens; + deposit.valability = valability; + deposit.expiration_round = self.get_expiration_round(valability); + deposit.esdt_funds = esdt_payment; + deposit.egld_funds = egld_payment; + }); + } + + #[endpoint(depositFees)] + #[payable("EGLD")] + fn deposit_fees(&self, address: ManagedAddress) { + let payment = self.call_value().egld_or_single_esdt(); + let accepted_fee_token = self.fee_token().get(); + require!( + payment.token_identifier == accepted_fee_token, + "Invalid fee token provided" + ); + let caller_address = self.blockchain().get_caller(); + let deposit_mapper = self.deposit(&address); + if !deposit_mapper.is_empty() { + deposit_mapper.update(|deposit| deposit.fees.value += payment.amount); + + return; + } + + let new_deposit = DepositInfo { + depositor_address: caller_address, + esdt_funds: ManagedVec::new(), + egld_funds: BigUint::zero(), + valability: 0, + expiration_round: 0, + fees: Fee { + num_token_to_transfer: 0, + value: payment.amount, + }, + }; + deposit_mapper.set(new_deposit); + } + + fn get_num_token_transfers( + &self, + egld_value: &BigUint, + esdt_transfers: &ManagedVec, + ) -> usize { + let mut amount = esdt_transfers.len(); + if egld_value > &0 { + amount += 1; + } + + amount + } + + fn get_expiration_round(&self, valability: u64) -> u64 { + let valability_rounds = valability / SECONDS_PER_ROUND; + self.blockchain().get_block_round() + valability_rounds + } +} diff --git a/contracts/examples/digital-cash/src/storage.rs b/contracts/examples/digital-cash/src/storage.rs new file mode 100644 index 0000000000..497b7bd86d --- /dev/null +++ b/contracts/examples/digital-cash/src/storage.rs @@ -0,0 +1,20 @@ +multiversx_sc::imports!(); +multiversx_sc::derive_imports!(); + +use crate::deposit_info::*; + +#[multiversx_sc::module] +pub trait StorageModule { + #[view] + #[storage_mapper("deposit")] + fn deposit(&self, donor: &ManagedAddress) -> SingleValueMapper>; + + #[storage_mapper("fee")] + fn fee(&self) -> SingleValueMapper; + + #[storage_mapper("feeToken")] + fn fee_token(&self) -> SingleValueMapper; + + #[storage_mapper("collectedFees")] + fn collected_fees(&self) -> SingleValueMapper; +}