Skip to content

Commit

Permalink
separate fee and fund endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
alyn509 committed Sep 19, 2023
1 parent 4b30eb5 commit cb5a873
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 110 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@
"address:digital_cash_owner_address": {
"nonce": "1",
"balance": "0",
"storage": "*"
"storage": {}
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions contracts/examples/digital-cash/src/constants.rs
Original file line number Diff line number Diff line change
@@ -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;
114 changes: 5 additions & 109 deletions contracts/examples/digital-cash/src/digital_cash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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<EsdtTokenPayment>,
) -> usize {
let mut amount = esdt_transfers.len();
if egld_value > &0 {
amount += 1;
}

amount
}

fn require_signature(
&self,
address: &ManagedAddress,
Expand All @@ -293,17 +202,4 @@ pub trait DigitalCash {
}

// storage

#[view]
#[storage_mapper("deposit")]
fn deposit(&self, donor: &ManagedAddress) -> SingleValueMapper<DepositInfo<Self::Api>>;

#[storage_mapper("fee")]
fn fee(&self) -> SingleValueMapper<BigUint>;

#[storage_mapper("feeToken")]
fn fee_token(&self) -> SingleValueMapper<EgldOrEsdtTokenIdentifier>;

#[storage_mapper("collectedFees")]
fn collected_fees(&self) -> SingleValueMapper<BigUint>;
}
95 changes: 95 additions & 0 deletions contracts/examples/digital-cash/src/pay_fee_and_fund.rs
Original file line number Diff line number Diff line change
@@ -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<EsdtTokenPayment>,
) -> 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
}
}
20 changes: 20 additions & 0 deletions contracts/examples/digital-cash/src/storage.rs
Original file line number Diff line number Diff line change
@@ -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<DepositInfo<Self::Api>>;

#[storage_mapper("fee")]
fn fee(&self) -> SingleValueMapper<BigUint>;

#[storage_mapper("feeToken")]
fn fee_token(&self) -> SingleValueMapper<EgldOrEsdtTokenIdentifier>;

#[storage_mapper("collectedFees")]
fn collected_fees(&self) -> SingleValueMapper<BigUint>;
}

0 comments on commit cb5a873

Please sign in to comment.