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

update the process of caclulate fee #98

Merged
merged 1 commit into from
Nov 11, 2022
Merged
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
14 changes: 9 additions & 5 deletions appchain/benchmarking/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,11 +302,13 @@ impl<T: Config> LposInterface<<T as frame_system::Config>::AccountId> for MockLp
}

parameter_types! {
pub const OctopusAppchainPalletId: PalletId = PalletId(*b"py/octps");
pub const GracePeriod: u32 = 10;
pub const UnsignedPriority: u64 = 1 << 21;
pub const RequestEventLimit: u32 = 10;
pub const UpwardMessagesLimit: u32 = 10;
pub const OctopusAppchainPalletId: PalletId = PalletId(*b"py/octps");
pub const GracePeriod: u32 = 10;
pub const UnsignedPriority: u64 = 1 << 21;
pub const RequestEventLimit: u32 = 10;
pub const UpwardMessagesLimit: u32 = 10;
pub const NativeTokenDecimals: u128 = 1_000_000_000_000_000_000;
pub const FeeTh: u64 = 300;
}

impl pallet_octopus_bridge::Config for Test {
Expand All @@ -323,6 +325,8 @@ impl pallet_octopus_bridge::Config for Test {
type ItemId = u128;
type Nonfungibles = pallet_octopus_bridge::impls::UnImplementUniques<Test>;
type Convertor = pallet_octopus_bridge::impls::ExampleConvertor<Test>;
type NativeTokenDecimals = NativeTokenDecimals;
type Threshold = FeeTh;
type WeightInfo = ();
}

Expand Down
7 changes: 7 additions & 0 deletions appchain/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,11 @@ impl pallet_uniques::Config for Test {
type Locker = ();
}

parameter_types! {
pub const NativeTokenDecimals: u128 = 1_000_000_000_000_000_000;
pub const FeeTh: u64 = 300;
}

impl pallet_octopus_bridge::Config for Test {
type RuntimeEvent = RuntimeEvent;
type PalletId = OctopusAppchainPalletId;
Expand All @@ -296,6 +301,8 @@ impl pallet_octopus_bridge::Config for Test {
type ItemId = u128;
type Nonfungibles = pallet_octopus_bridge::impls::UnImplementUniques<Test>;
type Convertor = pallet_octopus_bridge::impls::ExampleConvertor<Test>;
type NativeTokenDecimals = NativeTokenDecimals;
type Threshold = FeeTh;
type WeightInfo = ();
}

Expand Down
9 changes: 5 additions & 4 deletions bridge/benchmarking/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ fn set_oracle_account_and_update_token_price<T: BridgeConfig>() {
let ret = BridgePallet::<T>::set_oracle_account(RawOrigin::Root.into(), source);
assert!(ret.is_ok());
let origin = RawOrigin::Signed(caller.clone());
let ret = BridgePallet::<T>::set_token_price(origin.into(), 100);
let ret = BridgePallet::<T>::set_token_price(origin.into(), 11, 1_000_000_000_000);
assert!(ret.is_ok());
}

Expand Down Expand Up @@ -356,12 +356,13 @@ benchmarks! {
let _ = BridgePallet::<T>::set_oracle_account(RawOrigin::Root.into(), source);
let origin = RawOrigin::Signed(caller.clone());
}: {
let ret = BridgePallet::<T>::set_token_price(origin.into(), 1_000_000);
let ret = BridgePallet::<T>::set_token_price(origin.into(), 1_000_000, 2000_000);
}
verify {
assert_last_event::<T>(BridgeEvent::TokenPriceUpdated{
assert_last_event::<T>(BridgeEvent::PriceUpdated{
who: caller,
price: 1_000_000,
near_price: 1_000_000,
native_token_price: 2000_000,
}
.into());
}
Expand Down
4 changes: 4 additions & 0 deletions bridge/benchmarking/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,8 @@ parameter_types! {
pub const UnsignedPriority: u64 = 1 << 21;
pub const RequestEventLimit: u32 = 10;
pub const UpwardMessagesLimit: u32 = 10;
pub const NativeTokenDecimals: u128 = 1_000_000_000_000_000_000;
pub const Th: u64 = 300;
}

impl pallet_octopus_bridge::Config for Test {
Expand All @@ -322,6 +324,8 @@ impl pallet_octopus_bridge::Config for Test {
type ItemId = u128;
type Nonfungibles = pallet_octopus_bridge::impls::UnImplementUniques<Test>;
type Convertor = pallet_octopus_bridge::impls::ExampleConvertor<Test>;
type NativeTokenDecimals = NativeTokenDecimals;
type Threshold = Th;
type WeightInfo = ();
}

Expand Down
113 changes: 99 additions & 14 deletions bridge/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ use serde::Deserialize;
use serde_json::json;
use sp_runtime::{
traits::{AccountIdConversion, CheckedConversion, StaticLookup},
RuntimeDebug,
Perbill, RuntimeDebug,
};
use sp_std::prelude::*;
use weights::WeightInfo;
Expand Down Expand Up @@ -129,6 +129,12 @@ pub mod pallet {

type Convertor: ConvertIntoNep171<CollectionId = Self::CollectionId, ItemId = Self::ItemId>;

#[pallet::constant]
type NativeTokenDecimals: Get<u128>;

#[pallet::constant]
type Threshold: Get<u64>;

/// Type representing the weight of this pallet
type WeightInfo: WeightInfo;
}
Expand Down Expand Up @@ -328,10 +334,15 @@ pub mod pallet {
}

#[pallet::weight(<T as Config>::WeightInfo::set_token_price())]
pub fn set_token_price(origin: OriginFor<T>, price: u32) -> DispatchResult {
pub fn set_token_price(
origin: OriginFor<T>,
near_price: u64,
native_token_price: u64,
) -> DispatchResult {
let who = ensure_signed(origin)?;

ensure!(price != 0, Error::<T>::PriceIsZero);
ensure!(near_price != 0, Error::<T>::NearPriceSetedIsZero);
ensure!(native_token_price != 0, Error::<T>::NativeTokenPriceSetedIsZero);

let oracle_account = match <OracleAccount<T>>::try_get() {
Ok(account) => account,
Expand All @@ -340,13 +351,25 @@ pub mod pallet {

ensure!(who == oracle_account, Error::<T>::UpdatePriceWithNoPermissionAccount);

<TokenPrice<T>>::put(Some(price));
Self::calculate_and_update_fee(price);
<TokenPrice<T>>::put(Some(native_token_price));
<NearPrice<T>>::put(Some(near_price));

Self::calculate_and_update_fee(near_price, native_token_price);

Self::deposit_event(Event::TokenPriceUpdated { who, price });
Self::deposit_event(Event::PriceUpdated { who, near_price, native_token_price });

Ok(())
}

#[pallet::weight(0)]
pub fn set_coef_for_calculate_fee(origin: OriginFor<T>, coef: u32) -> DispatchResult {
ensure_root(origin)?;
ensure!(coef > 0 && coef <= 100, Error::<T>::InvalidCoef);

<Coef<T>>::put(coef);
Self::deposit_event(Event::CoefUpdated { coef });
Ok(())
}
}

#[pallet::event]
Expand Down Expand Up @@ -416,9 +439,13 @@ pub mod pallet {
OracleAccountHasBeenSet {
who: T::AccountId,
},
TokenPriceUpdated {
PriceUpdated {
who: T::AccountId,
price: u32,
near_price: u64,
native_token_price: u64,
},
CoefUpdated {
coef: u32,
},
}

Expand Down Expand Up @@ -450,12 +477,16 @@ pub mod pallet {
ConvertorNotImplement,
/// Not set oracle account.
NoOracleAccount,
/// Price is zero.
PriceIsZero,
/// Near price setted by oracle is zero.
NearPriceSetedIsZero,
/// Native token price setted by oracle is zero.
NativeTokenPriceSetedIsZero,
/// Update token price must use oracle account.
UpdatePriceWithNoPermissionAccount,
/// Invalid fee.
InvalidFee,
/// Invalid coef.
InvalidCoef,
}

/// A map from NEAR token account ID to appchain asset ID.
Expand All @@ -474,7 +505,20 @@ pub mod pallet {

/// Token price setted by oracle account.
#[pallet::storage]
pub(crate) type TokenPrice<T: Config> = StorageValue<_, Option<u32>, ValueQuery>;
pub(crate) type TokenPrice<T: Config> = StorageValue<_, Option<u64>, ValueQuery>;

/// Near price setted by oracle account.
#[pallet::storage]
pub(crate) type NearPrice<T: Config> = StorageValue<_, Option<u64>, ValueQuery>;

#[pallet::type_value]
pub(crate) fn DefaultForCoef() -> u32 {
3u32
}

/// Coef used to calculate fee for cross chain transactions.
#[pallet::storage]
pub(crate) type Coef<T: Config> = StorageValue<_, u32, ValueQuery, DefaultForCoef>;

#[pallet::genesis_config]
pub struct GenesisConfig<T: Config> {
Expand Down Expand Up @@ -530,9 +574,50 @@ impl<T: Config> Pallet<T> {
T::PalletId::get().into_account_truncating()
}

fn calculate_and_update_fee(price: u32) {
let ft_fee: BalanceOf<T> = (price / 4).checked_into().unwrap();
let nft_fee: BalanceOf<T> = (price / 2).checked_into().unwrap();
// Calcute:
// coef = <Coef<T>>::get() / 100,
// quantity = coef * near_native_token_price / wrapped_appchain_token_price,
// If quantity > threshold, then quantity = threshold.
fn calculate_quantity_of_native_tokens(
near_price: u64,
native_token_price: u64,
) -> (u64, Perbill) {
// (integer, fraction) = near_native_token_price / wrapped_appchain_token_price
let integer =
if near_price >= native_token_price { near_price / native_token_price } else { 0u64 };

let remain = near_price % native_token_price;
let fraction = Perbill::from_rational(remain, native_token_price);

// (integer1, fraction1) = integer * coef
let value1 = integer * (<Coef<T>>::get() as u64);
let integer1 = if value1 >= 100 { value1 / 100 } else { 0u64 };

if integer >= T::Threshold::get() {
return (T::Threshold::get(), Perbill::zero())
}

let remain1 = value1 % 100;
let fraction1 = Perbill::from_rational(remain1, 100);

// fraction2 = fraction * coef
let fraction2 = fraction * Perbill::from_rational(<Coef<T>>::get() as u64, 100);

// result = (coef * integer) + (coef * fraction)
// = (integer1, fraction1) + (0, fraction2)
(integer1, fraction1 + fraction2)
}

fn calculate_and_update_fee(near_price: u64, native_token_price: u64) {
let (integer, fraction) =
Self::calculate_quantity_of_native_tokens(near_price, native_token_price);

let fee_integer = T::NativeTokenDecimals::get() * (integer as u128);
let fee_fraction =
T::NativeTokenDecimals::get() * (fraction.deconstruct() as u128) / 1_000_000_000;
let ft_fee: BalanceOf<T> = (fee_integer + fee_fraction).checked_into().unwrap();
// Notes: should modify later.
let nft_fee = ft_fee;

<CrosschainTransferFee<T>>::insert(CrossChainTransferType::Fungible, Some(ft_fee));
<CrosschainTransferFee<T>>::insert(CrossChainTransferType::Nonfungible, Some(nft_fee));
Expand Down
4 changes: 4 additions & 0 deletions bridge/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,8 @@ parameter_types! {
pub const RequestEventLimit: u32 = 10;
pub const UpwardMessagesLimit: u32 = 10;
pub const MaxValidators: u32 = 10 ;
pub const NativeTokenDecimals: u128 = 1_000_000_000_000_000_000;
pub const FeeTh: u64 = 300;
}

impl pallet_octopus_appchain::Config for Test {
Expand Down Expand Up @@ -322,6 +324,8 @@ impl Config for Test {
type ItemId = u128;
type Nonfungibles = Uniques;
type Convertor = pallet_octopus_bridge::impls::ExampleConvertor<Test>;
type NativeTokenDecimals = NativeTokenDecimals;
type Threshold = FeeTh;
type WeightInfo = ();
}

Expand Down
50 changes: 42 additions & 8 deletions bridge/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -315,29 +315,63 @@ pub fn test_set_token_price() {
let origin2 = RuntimeOrigin::signed(bob);
new_tester().execute_with(|| {
assert_noop!(
OctopusBridge::set_token_price(origin1.clone(), 1000000),
OctopusBridge::set_token_price(origin1.clone(), 1000, 1000),
Error::<Test>::NoOracleAccount
);
assert_ok!(OctopusBridge::set_oracle_account(RuntimeOrigin::root(), source.clone()));

assert_noop!(
OctopusBridge::set_token_price(origin2, 1000000),
OctopusBridge::set_token_price(origin2, 1000, 1000),
Error::<Test>::UpdatePriceWithNoPermissionAccount
);
assert_noop!(
OctopusBridge::set_token_price(origin1.clone(), 0),
Error::<Test>::PriceIsZero
OctopusBridge::set_token_price(origin1.clone(), 0, 0),
Error::<Test>::NearPriceSetedIsZero
);
assert_ok!(OctopusBridge::set_token_price(origin1, 1000000));
assert_noop!(
OctopusBridge::set_token_price(origin1.clone(), 1000, 0),
Error::<Test>::NativeTokenPriceSetedIsZero
);
assert_ok!(OctopusBridge::set_token_price(origin1.clone(), 1000, 1000));

assert_eq!(TokenPrice::<Test>::get(), Some(1000000));
assert_eq!(TokenPrice::<Test>::get(), Some(1000));
assert_eq!(
CrosschainTransferFee::<Test>::get(CrossChainTransferType::Fungible).unwrap(),
Some(250000)
Some(30_000_000_000_000_000)
);
assert_eq!(
CrosschainTransferFee::<Test>::get(CrossChainTransferType::Nonfungible).unwrap(),
Some(500000)
Some(30_000_000_000_000_000)
);

assert_ok!(OctopusBridge::set_token_price(origin1.clone(), 3_119_000, 6_620_000));
assert_eq!(
CrosschainTransferFee::<Test>::get(CrossChainTransferType::Fungible).unwrap(),
Some(14_134_441_000_000_000)
);

assert_ok!(OctopusBridge::set_token_price(origin1.clone(), 3_119_000, 20_535_200_000));
assert_eq!(
CrosschainTransferFee::<Test>::get(CrossChainTransferType::Fungible).unwrap(),
Some(4_556_000_000_000)
);

assert_ok!(OctopusBridge::set_token_price(origin1.clone(), 3_119_000, 41_000));
assert_eq!(
CrosschainTransferFee::<Test>::get(CrossChainTransferType::Fungible).unwrap(),
Some(2_282_195_121_000_000_000)
);

assert_ok!(OctopusBridge::set_token_price(origin1.clone(), 3_119_000, 1));
assert_eq!(
CrosschainTransferFee::<Test>::get(CrossChainTransferType::Fungible).unwrap(),
Some(300_000_000_000_000_000_000)
);

assert_ok!(OctopusBridge::set_token_price(origin1, 3_119_000, 3_119_000));
assert_eq!(
CrosschainTransferFee::<Test>::get(CrossChainTransferType::Fungible).unwrap(),
Some(30_000_000_000_000_000)
);
});
}
Loading