Skip to content
Closed
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
35 changes: 17 additions & 18 deletions contracts/examples/order-book/pair/src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,10 @@ pub enum OrderType {
Sell,
}

/// TODO: naming conflict with new FungiblePayment type in the framework, switch to that
#[derive(ManagedVecItem, Clone)]
pub struct OrderBookFungiblePayment<M: ManagedTypeApi> {
pub token_id: TokenId<M>,
pub amount: BigUint<M>,
}

#[derive(ManagedVecItem, Clone)]
pub struct Transfer<M: ManagedTypeApi> {
pub to: ManagedAddress<M>,
pub payment: OrderBookFungiblePayment<M>,
pub payment: FungiblePayment<M>,
}

#[type_abi]
Expand All @@ -52,7 +45,7 @@ pub struct DealConfig {
#[type_abi]
#[derive(TopEncode, TopDecode, Clone)]
pub struct OrderInputParams<M: ManagedTypeApi> {
pub amount: BigUint<M>,
pub amount: NonZeroBigUint<M>,
pub match_provider: ManagedAddress<M>,
pub fee_config: FeeConfig<M>,
pub deal_config: DealConfig,
Expand All @@ -64,8 +57,8 @@ pub struct Order<M: ManagedTypeApi> {
pub id: u64,
pub creator: ManagedAddress<M>,
pub match_provider: ManagedAddress<M>,
pub input_amount: BigUint<M>,
pub output_amount: BigUint<M>,
pub input_amount: NonZeroBigUint<M>,
pub output_amount: NonZeroBigUint<M>,
pub fee_config: FeeConfig<M>,
pub deal_config: DealConfig,
pub create_epoch: u64,
Expand All @@ -84,7 +77,7 @@ pub trait CommonModule {
fn new_order(
&self,
id: u64,
payment: OrderBookFungiblePayment<Self::Api>,
payment: FungiblePayment<Self::Api>,
params: OrderInputParams<Self::Api>,
order_type: OrderType,
) -> Order<Self::Api> {
Expand All @@ -101,23 +94,29 @@ pub trait CommonModule {
}
}

fn rule_of_three(&self, part: &BigUint, total: &BigUint, value: &BigUint) -> BigUint {
&(part * value) / total
fn rule_of_three(&self, part: u64, total: u64, value: &BigUint) -> BigUint {
&(BigUint::from(part) * value) / BigUint::from(total)
}

fn calculate_fee_amount(&self, amount: &BigUint, fee_config: &FeeConfig<Self::Api>) -> BigUint {
fn calculate_fee_amount(
&self,
amount: &NonZeroBigUint,
fee_config: &FeeConfig<Self::Api>,
) -> BigUint {
match fee_config.fee_type {
FeeConfigEnum::Fixed => fee_config.fixed_fee.clone(),
FeeConfigEnum::Percent => amount * fee_config.percent_fee / PERCENT_BASE_POINTS,
FeeConfigEnum::Percent => amount
.as_big_uint()
.proportion(fee_config.percent_fee, PERCENT_BASE_POINTS),
}
}

fn calculate_amount_after_fee(
&self,
amount: &BigUint,
amount: &NonZeroBigUint,
fee_config: &FeeConfig<Self::Api>,
) -> BigUint {
amount - &self.calculate_fee_amount(amount, fee_config)
amount.as_big_uint() - &self.calculate_fee_amount(amount, fee_config)
}

#[view(getFirstTokenId)]
Expand Down
103 changes: 48 additions & 55 deletions contracts/examples/order-book/pair/src/orders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use crate::common::{FEE_PENALTY_INCREASE_EPOCHS, FEE_PENALTY_INCREASE_PERCENT};
use super::{common, events, validation};

use super::common::{
FREE_ORDER_FROM_STORAGE_MIN_PENALTIES, Order, OrderBookFungiblePayment, OrderInputParams,
OrderType, PERCENT_BASE_POINTS, Transfer,
FREE_ORDER_FROM_STORAGE_MIN_PENALTIES, Order, OrderInputParams, OrderType, PERCENT_BASE_POINTS,
Transfer,
};

#[multiversx_sc::module]
Expand All @@ -15,7 +15,7 @@ pub trait OrdersModule:
{
fn create_order(
&self,
payment: OrderBookFungiblePayment<Self::Api>,
payment: FungiblePayment<Self::Api>,
params: OrderInputParams<Self::Api>,
order_type: OrderType,
) {
Expand Down Expand Up @@ -150,27 +150,22 @@ pub trait OrdersModule:
"Too early to free order"
);

// penalty_count is > 6, so this cannot be zero
let penalty_percent = penalty_count * FEE_PENALTY_INCREASE_PERCENT;
let penalty_amount = self.rule_of_three(
&BigUint::from(penalty_percent),
&BigUint::from(PERCENT_BASE_POINTS),
&order.input_amount,
);
let amount = &order.input_amount - &penalty_amount;

let penalty_amount = order
.input_amount
.proportion(penalty_percent, PERCENT_BASE_POINTS);

let creator_amount = &order.input_amount - &penalty_amount;

let creator_transfer = Transfer {
to: order.creator.clone(),
payment: OrderBookFungiblePayment {
token_id: token_id.clone(),
amount,
},
payment: FungiblePayment::new(token_id.clone(), creator_amount),
};
let caller_transfer = Transfer {
to: caller.clone(),
payment: OrderBookFungiblePayment {
token_id,
amount: penalty_amount,
},
payment: FungiblePayment::new(token_id, penalty_amount),
};

self.orders(order_id).clear();
Expand Down Expand Up @@ -199,16 +194,16 @@ pub trait OrdersModule:

let penalty_count = (epoch - order.create_epoch) / FEE_PENALTY_INCREASE_EPOCHS;
let penalty_percent = penalty_count * FEE_PENALTY_INCREASE_PERCENT;
let penalty_amount = self.rule_of_three(
&BigUint::from(penalty_percent),
&BigUint::from(PERCENT_BASE_POINTS),
&order.input_amount,
);
let amount = &order.input_amount - &penalty_amount;
let penalty_amount = order
.input_amount
.proportion(penalty_percent, PERCENT_BASE_POINTS);

let mut amount = order.input_amount.clone();
amount -= &penalty_amount;

let transfer = Transfer {
to: caller.clone(),
payment: OrderBookFungiblePayment { token_id, amount },
payment: FungiblePayment::new(token_id, amount),
};

self.orders(order_id).clear();
Expand Down Expand Up @@ -297,8 +292,8 @@ pub trait OrdersModule:
let mut amount_requested = BigUint::zero();

orders.iter().for_each(|x| {
amount_paid += &x.input_amount;
amount_requested += &x.output_amount;
amount_paid += x.input_amount.as_big_uint();
amount_requested += x.output_amount.as_big_uint();
});

(amount_paid, amount_requested)
Expand All @@ -312,54 +307,52 @@ pub trait OrdersModule:
leftover: BigUint,
) -> ManagedVec<Transfer<Self::Api>> {
let mut transfers: ManagedVec<Self::Api, Transfer<Self::Api>> = ManagedVec::new();

let mut match_provider_transfer = Transfer {
to: self.blockchain().get_caller(),
payment: OrderBookFungiblePayment {
token_id: token_requested.clone(),
amount: BigUint::zero(),
},
};
let mut match_provider_amount_accumulator = BigUint::zero();

for order in orders.iter() {
let match_provider_amount =
self.calculate_fee_amount(&order.output_amount, &order.fee_config);
let creator_amount = &order.output_amount - &match_provider_amount;
let creator_amount = order.output_amount.as_big_uint() - &match_provider_amount;

let order_deal = self.rule_of_three(&order.input_amount, &total_paid, &leftover);
let match_provider_deal_amount = self.rule_of_three(
&order.deal_config.match_provider_percent.into(),
&PERCENT_BASE_POINTS.into(),
&order_deal,
let order_deal = order.input_amount.as_big_uint() * &leftover / &total_paid;
let match_provider_deal_amount = order_deal.proportion(
order.deal_config.match_provider_percent,
PERCENT_BASE_POINTS,
);
let creator_deal_amount = &order_deal - &match_provider_deal_amount;

transfers.push(Transfer {
to: order.creator.clone(),
payment: OrderBookFungiblePayment {
token_id: token_requested.clone(),
amount: creator_amount + creator_deal_amount,
},
payment: FungiblePayment::new(
token_requested.clone(),
NonZeroBigUint::new_or_panic(creator_amount + creator_deal_amount),
),
});

match_provider_transfer.payment.amount +=
match_provider_amount + match_provider_deal_amount;
match_provider_amount_accumulator += match_provider_amount + match_provider_deal_amount;
}

if match_provider_amount_accumulator > 0 {
transfers.push(Transfer {
to: self.blockchain().get_caller(),
payment: FungiblePayment::new(
token_requested.clone(),
NonZeroBigUint::new_or_panic(match_provider_amount_accumulator),
),
});
}
transfers.push(match_provider_transfer);

transfers
}

fn execute_transfers(&self, transfers: ManagedVec<Transfer<Self::Api>>) {
for transfer in &transfers {
if transfer.payment.amount > 0 {
let token_id = transfer.payment.token_id.clone();
let amount = NonZeroBigUint::new(transfer.payment.amount.clone()).unwrap();
self.tx()
.to(&transfer.to)
.payment(Payment::new(token_id, 0, amount))
.transfer();
}
let token_id = transfer.payment.token_identifier.clone();
let amount = transfer.payment.amount.clone();
self.tx()
.to(&transfer.to)
.payment(Payment::new(token_id, 0, amount))
.transfer();
}
}

Expand Down
23 changes: 7 additions & 16 deletions contracts/examples/order-book/pair/src/validation.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
use multiversx_sc::imports::*;

use crate::common::{FeeConfig, FeeConfigEnum, OrderBookFungiblePayment};

use super::{
common,
common::{
FEE_PENALTY_INCREASE_PERCENT, MAX_ORDERS_PER_USER, Order, OrderInputParams,
PERCENT_BASE_POINTS,
FEE_PENALTY_INCREASE_PERCENT, FeeConfig, FeeConfigEnum, MAX_ORDERS_PER_USER, Order,
OrderInputParams, PERCENT_BASE_POINTS,
},
};

#[multiversx_sc::module]
pub trait ValidationModule: common::CommonModule {
fn require_valid_order_input_amount(&self, params: &OrderInputParams<Self::Api>) {
require!(params.amount != BigUint::zero(), "Amount cannot be zero");
require!(
self.calculate_fee_amount(
&params.amount,
Expand All @@ -38,7 +35,7 @@ pub trait ValidationModule: common::CommonModule {
match params.fee_config.fee_type.clone() {
FeeConfigEnum::Fixed => {
require!(
params.fee_config.fixed_fee < params.amount,
params.fee_config.fixed_fee < *params.amount.as_big_uint(),
"Invalid fee config fixed amount"
);
}
Expand Down Expand Up @@ -68,7 +65,7 @@ pub trait ValidationModule: common::CommonModule {
self.require_valid_order_input_deal_config(params);
}

fn require_valid_buy_payment(&self) -> OrderBookFungiblePayment<Self::Api> {
fn require_valid_buy_payment(&self) -> FungiblePayment<Self::Api> {
let payment = self.call_value().single();
let second_token_id = self.second_token_id().get();
require!(
Expand All @@ -80,13 +77,10 @@ pub trait ValidationModule: common::CommonModule {
"Token id and second token id should be the same"
);

OrderBookFungiblePayment {
token_id: payment.token_identifier.clone(),
amount: payment.amount.as_big_uint().clone(),
}
FungiblePayment::new(payment.token_identifier.clone(), payment.amount.clone())
}

fn require_valid_sell_payment(&self) -> OrderBookFungiblePayment<Self::Api> {
fn require_valid_sell_payment(&self) -> FungiblePayment<Self::Api> {
let payment = self.call_value().single();
let first_token_id = self.first_token_id().get();
require!(payment.is_fungible(), "Payment is not a fungible token");
Expand All @@ -95,10 +89,7 @@ pub trait ValidationModule: common::CommonModule {
"Token id and first token id should be the same"
);

OrderBookFungiblePayment {
token_id: payment.token_identifier.clone(),
amount: payment.amount.as_big_uint().clone(),
}
FungiblePayment::new(payment.token_identifier.clone(), payment.amount.clone())
}

fn require_valid_match_input_order_ids(&self, order_ids: &ManagedVec<u64>) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ pub trait BigIntMethods {
}

#[endpoint]
fn bigint_overwrite_i64(&self, bi: BigInt, small: i64) -> BigInt {
fn bigint_overwrite_i64(&self, mut bi: BigInt, small: i64) -> BigInt {
bi.overwrite_i64(small);
bi
}
Expand Down
30 changes: 29 additions & 1 deletion framework/base/src/types/managed/basic/big_int.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ impl<M: ManagedTypeApi> BigInt<M> {
}

#[inline]
pub fn overwrite_i64(&self, value: i64) {
pub fn overwrite_i64(&mut self, value: i64) {
Self::set_value(self.handle.clone(), value);
}

Expand Down Expand Up @@ -372,6 +372,34 @@ impl<M: ManagedTypeApi> BigInt<M> {
result
}
}

/// Calculates proportion of this value, consuming self.
///
/// # Arguments
/// * `part` - The numerator value (can be negative)
/// * `total` - The denominator value for the ratio calculation
///
/// # Returns
/// The proportional amount as BigInt (self * part / total)
pub fn into_proportion(mut self, part: i64, total: i64) -> Self {
let mut temp = BigInt::from(part);
self *= &temp;
temp.overwrite_i64(total);
self /= &temp;
self
}

/// Calculates proportion of this value.
///
/// # Arguments
/// * `part` - The numerator value (can be negative)
/// * `total` - The denominator value for the ratio calculation
///
/// # Returns
/// The proportional amount as BigInt (self * part / total)
pub fn proportion(&self, part: i64, total: i64) -> Self {
self.clone().into_proportion(part, total)
}
}

impl<M: ManagedTypeApi> SCDisplay for BigInt<M> {
Expand Down
Loading
Loading