Skip to content

Commit d600485

Browse files
authored
Modify bancor (#190)
* - modity add_token_to_pool call to support initial token adding by any account who has enough token balance. - add functionalities to on_initialize hook to release certain amount of token by every block. * cargo +nightly fmt --all * cargo +nightly fmt --all
1 parent 350ff07 commit d600485

6 files changed

Lines changed: 189 additions & 71 deletions

File tree

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pallets/bancor/src/lib.rs

Lines changed: 114 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ type AccountIdOf<T> = <T as frame_system::Config>::AccountId;
4040
type BalanceOf<T> = <<T as Config>::MultiCurrency as MultiCurrency<AccountIdOf<T>>>::Balance;
4141

4242
const BILLION: u128 = 1_000_000_000;
43+
// These time units are defined in number of blocks.
44+
const BLOCKS_PER_DAY: u32 = 60 / 12 * 60 * 24;
4345

4446
#[derive(Encode, Decode, Clone, Eq, PartialEq, Debug)]
4547
pub struct BancorPool<Balance> {
@@ -63,6 +65,9 @@ pub mod pallet {
6365
#[pallet::constant]
6466
type InterventionPercentage: Get<Percent>;
6567

68+
#[pallet::constant]
69+
type DailyReleasePercentage: Get<Percent>;
70+
6671
/// Set default weight.
6772
type WeightInfo: WeightInfo;
6873
}
@@ -97,6 +102,11 @@ pub mod pallet {
97102
#[pallet::getter(fn get_bancor_pool)]
98103
pub type BancorPools<T> = StorageMap<_, Blake2_128Concat, CurrencyId, BancorPool<BalanceOf<T>>>;
99104

105+
/// Reserve for releasing Tokens to the bancor pool
106+
#[pallet::storage]
107+
#[pallet::getter(fn get_bancor_reserve)]
108+
pub type BancorReserve<T> = StorageMap<_, Blake2_128Concat, CurrencyId, BalanceOf<T>>;
109+
100110
#[pallet::genesis_config]
101111
pub struct GenesisConfig<T: Config> {
102112
pub bancor_pools: Vec<(CurrencyId, BalanceOf<T>)>,
@@ -122,7 +132,8 @@ pub mod pallet {
122132
vstoken_base_supply: *base_balance,
123133
};
124134

125-
BancorPools::<T>::insert(currency_id, pool);
135+
BancorPools::<T>::insert(currency_id.clone(), pool);
136+
BancorReserve::<T>::insert(currency_id.clone(), BalanceOf::<T>::from(0u32));
126137
}
127138
}
128139
}
@@ -131,7 +142,91 @@ pub mod pallet {
131142
pub struct Pallet<T>(PhantomData<T>);
132143

133144
#[pallet::hooks]
134-
impl<T: Config> Hooks<T::BlockNumber> for Pallet<T> {}
145+
impl<T: Config> Hooks<T::BlockNumber> for Pallet<T> {
146+
// check whether the price of vstoken (token/vstoken) is lower than 75%. if yes, then half
147+
// of this newly released token should be used to buy vstoken, so that the price of vstoken
148+
// will increase. Meanwhile, the other half will be put on the ceiling variable to indicate
149+
// exchange availability. If not, all the newly release token should be put aside to the
150+
// ceiling to not to impact the pool price.
151+
fn on_initialize(_: T::BlockNumber) -> Weight {
152+
// for each bancor pool currency_id, release 5% of reserve tokens to the pool
153+
for (currency_id, reserve_amount) in BancorReserve::<T>::iter() {
154+
let token_amount = reserve_amount /
155+
T::DailyReleasePercentage::get()
156+
.saturating_reciprocal_mul_floor(BalanceOf::<T>::from(BLOCKS_PER_DAY));
157+
158+
if token_amount > Zero::zero() {
159+
// get the current price of vstoken
160+
// let (nominator, denominator) = Self::get_instant_vstoken_price(currency_id);
161+
if let Ok((nominator, denominator)) =
162+
Self::get_instant_vstoken_price(currency_id)
163+
{
164+
let amount_kept: BalanceOf<T>;
165+
// if vstoken price is lower than 0.75 token
166+
if T::InterventionPercentage::get()
167+
.saturating_reciprocal_mul_floor(nominator) <=
168+
denominator
169+
{
170+
amount_kept = token_amount / BalanceOf::<T>::saturated_from(2u128);
171+
} else {
172+
amount_kept = token_amount;
173+
}
174+
175+
let sell_amount = token_amount.saturating_sub(amount_kept);
176+
// deal with ceiling variable
177+
if amount_kept != Zero::zero() {
178+
if let Err(_) =
179+
Self::increase_bancor_pool_ceiling(currency_id, amount_kept)
180+
{
181+
continue;
182+
}
183+
}
184+
// deal with exchange transaction
185+
if sell_amount != Zero::zero() {
186+
// make changes in the bancor pool
187+
if let Ok(vstoken_amount) =
188+
Self::calculate_price_for_vstoken(currency_id, sell_amount)
189+
{
190+
let sell_result = Self::revise_bancor_pool_token_buy_vstoken(
191+
currency_id,
192+
sell_amount,
193+
vstoken_amount,
194+
);
195+
// if somehow not able to sell token, then add the amount to
196+
// ceiling.
197+
if let Err(err_msg) = sell_result {
198+
match err_msg {
199+
Error::<T>::BancorPoolNotExist => (),
200+
_ => {
201+
if let Err(_) = Self::increase_bancor_pool_ceiling(
202+
currency_id,
203+
sell_amount,
204+
) {
205+
continue;
206+
}
207+
},
208+
};
209+
}
210+
}
211+
}
212+
213+
// deduct token_amount from BancorReserve
214+
BancorReserve::<T>::mutate(currency_id, |reserve_option| {
215+
match reserve_option {
216+
Some(reserve) => {
217+
*reserve = reserve.saturating_sub(token_amount);
218+
},
219+
_ => (),
220+
}
221+
});
222+
}
223+
}
224+
}
225+
226+
// TODO: Estimate weight for this function
227+
1_000
228+
}
229+
}
135230

136231
#[pallet::call]
137232
impl<T: Config> Pallet<T> {
@@ -141,9 +236,13 @@ pub mod pallet {
141236
currency_id: CurrencyId,
142237
token_amount: BalanceOf<T>,
143238
) -> DispatchResult {
144-
ensure_root(origin)?;
239+
let adder = ensure_signed(origin)?;
145240
ensure!(currency_id.is_token(), Error::<T>::NotSupportTokenType);
146241

242+
let token_balance = T::MultiCurrency::free_balance(currency_id, &adder);
243+
ensure!(token_balance >= token_amount, Error::<T>::NotEnoughBalance);
244+
245+
T::MultiCurrency::withdraw(currency_id, &adder, token_amount)?;
147246
Self::add_token(currency_id, token_amount)?;
148247

149248
Ok(())
@@ -426,49 +525,19 @@ impl<T: Config> Pallet<T> {
426525
}
427526

428527
impl<T: Config> BancorHandler<BalanceOf<T>> for Pallet<T> {
429-
// check whether the price of vstoken (token/vstoken) is lower than 75%. if yes, then half of
430-
// this newly released token should be used to buy vstoken, so that the price of vstoken will
431-
// increase. Meanwhile, the other half will be put on the ceiling variable to indicate exchange
432-
// availability. If not, all the newly release token should be put aside to the ceiling to not
433-
// to impact the pool price.
434528
fn add_token(currency_id: CurrencyId, token_amount: BalanceOf<T>) -> Result<(), DispatchError> {
435-
// get the current price of vstoken
436-
let (nominator, denominator) = Self::get_instant_vstoken_price(currency_id)?;
437-
438-
let amount_kept: BalanceOf<T>;
439-
// if vstoken price is lower than 0.75 token
440-
if T::InterventionPercentage::get().saturating_reciprocal_mul_floor(nominator) <=
441-
denominator
442-
{
443-
amount_kept = token_amount / BalanceOf::<T>::saturated_from(2u128);
444-
} else {
445-
amount_kept = token_amount;
446-
}
447-
448-
let sell_amount = token_amount.saturating_sub(amount_kept);
449-
450-
// deal with ceiling variable
451-
if amount_kept != Zero::zero() {
452-
Self::increase_bancor_pool_ceiling(currency_id, amount_kept)?;
453-
}
454-
455-
// deal with exchange transaction
456-
if sell_amount != Zero::zero() {
457-
// make changes in the bancor pool
458-
let vstoken_amount = Self::calculate_price_for_vstoken(currency_id, sell_amount)?;
459-
let sell_result = Self::revise_bancor_pool_token_buy_vstoken(
460-
currency_id,
461-
sell_amount,
462-
vstoken_amount,
463-
);
464-
465-
// if somehow not able to sell token, then add the amount to ceiling.
466-
if let Err(err_msg) = sell_result {
467-
match err_msg {
468-
Error::<T>::BancorPoolNotExist => Err(Error::<T>::BancorPoolNotExist),
469-
_ => Self::increase_bancor_pool_ceiling(currency_id, sell_amount),
470-
}?;
471-
}
529+
ensure!(token_amount >= Zero::zero(), Error::<T>::AmountNotGreaterThanZero);
530+
531+
if token_amount != Zero::zero() {
532+
BancorReserve::<T>::mutate(currency_id, |reserve_option| -> Result<(), Error<T>> {
533+
match reserve_option {
534+
Some(reserve) => {
535+
*reserve = reserve.saturating_add(token_amount);
536+
Ok(())
537+
},
538+
_ => Err(Error::<T>::BancorPoolNotExist),
539+
}
540+
})?;
472541
}
473542

474543
Ok(())

pallets/bancor/src/mock.rs

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@
1818

1919
#![cfg(test)]
2020

21-
use frame_support::{construct_runtime, parameter_types, traits::GenesisBuild};
21+
use frame_support::{
22+
construct_runtime, parameter_types,
23+
traits::{GenesisBuild, OnFinalize, OnInitialize},
24+
};
2225
pub use node_primitives::{Balance, CurrencyId, TokenSymbol};
2326
use sp_core::H256;
2427
use sp_runtime::{
@@ -109,11 +112,13 @@ impl orml_tokens::Config for Test {
109112

110113
parameter_types! {
111114
pub const InterventionPercentage: Percent = Percent::from_percent(75);
115+
pub const DailyReleasePercentage: Percent = Percent::from_percent(5);
112116
}
113117

114118
impl bancor::Config for Test {
115119
type Event = Event;
116120
type InterventionPercentage = InterventionPercentage;
121+
type DailyReleasePercentage = DailyReleasePercentage;
117122
type MultiCurrency = Tokens;
118123
type WeightInfo = ();
119124
}
@@ -147,16 +152,16 @@ impl ExtBuilder {
147152
])
148153
}
149154

150-
pub fn hundred_thousand_for_alice_n_bob(self) -> Self {
155+
pub fn thousand_thousand_for_alice_n_bob(self) -> Self {
151156
self.balances(vec![
152-
(ALICE, KSM, 100_000),
153-
(ALICE, DOT, 100_000),
154-
(ALICE, VSKSM, 100_000),
155-
(ALICE, VSDOT, 100_000),
156-
(BOB, KSM, 100_000),
157-
(BOB, DOT, 100_000),
158-
(BOB, VSKSM, 100_000),
159-
(BOB, VSDOT, 100_000),
157+
(ALICE, KSM, 1_000_000),
158+
(ALICE, DOT, 1_000_000),
159+
(ALICE, VSKSM, 1_000_000),
160+
(ALICE, VSDOT, 1_000_000),
161+
(BOB, KSM, 1_000_000),
162+
(BOB, DOT, 1_000_000),
163+
(BOB, VSKSM, 1_000_000),
164+
(BOB, VSDOT, 1_000_000),
160165
])
161166
}
162167

@@ -179,3 +184,14 @@ impl ExtBuilder {
179184
t.into()
180185
}
181186
}
187+
188+
// simulate block production
189+
pub(crate) fn run_to_block(n: u64) {
190+
while System::block_number() < n {
191+
Bancor::on_finalize(System::block_number());
192+
System::on_finalize(System::block_number());
193+
System::set_block_number(System::block_number() + 1);
194+
System::on_initialize(System::block_number());
195+
Bancor::on_initialize(System::block_number());
196+
}
197+
}

0 commit comments

Comments
 (0)