Skip to content

Commit

Permalink
add donation functions and mft_unregister
Browse files Browse the repository at this point in the history
  • Loading branch information
MagicGordon committed Oct 9, 2024
1 parent 88f385f commit 085aa66
Show file tree
Hide file tree
Showing 14 changed files with 289 additions and 3 deletions.
6 changes: 4 additions & 2 deletions ref-exchange/release_notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

### Version 1.9.7
```
Cc7rca9tb9CZKQRkm5fqXMErVuCcGr3aeoxNsUgmkVhX
B2646W6czcBc6AnZfb4uETrAfcptNicVuYeiraoZFKA8
```
1. fix identity verification for the whitelisted_postfix related interfaces.
1. fix identity verification for the whitelisted_postfix related functions.
2. add donation functions.
3. add mft_unregister.

### Version 1.9.6
```
Expand Down
7 changes: 7 additions & 0 deletions ref-exchange/src/degen_swap/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -717,6 +717,13 @@ impl DegenSwapPool {
self.shares.insert(account_id, &0);
}

/// Unregister account with shares balance of 0.
/// The storage should be refunded to the user.
pub fn share_unregister(&mut self, account_id: &AccountId) {
let shares = self.shares.remove(account_id);
assert!(shares.expect(ERR13_LP_NOT_REGISTERED) == 0, "{}", ERR19_LP_NOT_EMPTY);
}

/// Transfers shares from predecessor to receiver.
pub fn share_transfer(&mut self, sender_id: &AccountId, receiver_id: &AccountId, amount: u128) {
let balance = self.shares.get(&sender_id).expect(ERR13_LP_NOT_REGISTERED);
Expand Down
47 changes: 47 additions & 0 deletions ref-exchange/src/donation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use crate::*;

#[near_bindgen]
impl Contract {
#[payable]
pub fn donation_share(&mut self, pool_id: u64, amount: Option<U128>, unregister: Option<bool>) {
assert_one_yocto();
let account_id = env::predecessor_account_id();
let prev_storage = env::storage_usage();
let mut pool = self.pools.get(pool_id).expect(ERR85_NO_POOL);
let donation_amount = amount.map(|v| v.0).unwrap_or(pool.share_balances(&account_id));
assert!(donation_amount > 0, "Invalid amount");
pool.share_transfer(&account_id, &env::current_account_id(), donation_amount);
if unregister == Some(true) {
pool.share_unregister(&account_id);
}
self.pools.replace(pool_id, &pool);
if prev_storage > env::storage_usage() {
let refund = (prev_storage - env::storage_usage()) as Balance * env::storage_byte_cost();
if let Some(mut account) = self.internal_get_account(&account_id) {
account.near_amount += refund;
self.internal_save_account(&account_id, account);
} else {
Promise::new(account_id.clone()).transfer(refund);
}
}
event::Event::DonationShare { account_id: &account_id, pool_id, amount: U128(donation_amount) }.emit();
}

#[payable]
pub fn donation_token(&mut self, token_id: ValidAccountId, amount: Option<U128>, unregister: Option<bool>) {
assert_one_yocto();
let account_id = env::predecessor_account_id();
let mut account = self.internal_unwrap_account(&account_id);
let donation_amount = amount.map(|v| v.0).unwrap_or(account.get_balance(token_id.as_ref()).expect("Invalid token_id"));
assert!(donation_amount > 0, "Invalid amount");
account.withdraw(token_id.as_ref(), donation_amount);
if unregister == Some(true) {
account.unregister(token_id.as_ref());
}
self.internal_save_account(&account_id, account);
let mut owner_account = self.internal_unwrap_account(&self.owner_id);
owner_account.deposit(token_id.as_ref(), donation_amount);
self.accounts.insert(&self.owner_id, &owner_account.into());
event::Event::DonationToken { account_id: &account_id, token_id: token_id.as_ref(), amount: U128(donation_amount) }.emit();
}
}
2 changes: 2 additions & 0 deletions ref-exchange/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub const ERR15_NO_STORAGE_CAN_WITHDRAW: &str = "E15: no storage can withdraw";
pub const ERR16_STORAGE_WITHDRAW_TOO_MUCH: &str = "E16: storage withdraw too much";
pub const ERR17_DEPOSIT_LESS_THAN_MIN_STORAGE: &str = "E17: deposit less than min storage";
pub const ERR18_TOKENS_NOT_EMPTY: &str = "E18: storage unregister tokens not empty";
pub const ERR19_LP_NOT_EMPTY: &str = "E19: LP not empty";

// Accounts.

Expand Down Expand Up @@ -90,6 +91,7 @@ pub const ERR105_WHITELISTED_POSTFIX_NOT_IN_LIST: &str = "E105: whitelisted post

//mft
pub const ERR110_INVALID_REGISTER: &str = "E110: Invalid register";
pub const ERR111_INVALID_UNREGISTER: &str = "E111: Invalid unregister";

// rated pool
pub const ERR120_RATES_EXPIRED: &str = "E120: Rates expired";
Expand Down
38 changes: 38 additions & 0 deletions ref-exchange/src/event.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@

use crate::*;
use near_sdk::serde_json::json;

const EVENT_STANDARD: &str = "exchange.ref";
const EVENT_STANDARD_VERSION: &str = "1.0.0";

#[derive(Serialize, Debug, Clone)]
#[serde(crate = "near_sdk::serde")]
#[serde(tag = "event", content = "data")]
#[serde(rename_all = "snake_case")]
#[must_use = "Don't forget to `.emit()` this event"]
pub enum Event<'a> {
DonationShare {
account_id: &'a AccountId,
pool_id: u64,
amount: U128,
},
DonationToken {
account_id: &'a AccountId,
token_id: &'a AccountId,
amount: U128,
}
}

impl Event<'_> {
pub fn emit(&self) {
let data = json!(self);
let event_json = json!({
"standard": EVENT_STANDARD,
"version": EVENT_STANDARD_VERSION,
"event": data["event"],
"data": [data["data"]]
})
.to_string();
log!("EVENT_JSON:{}", event_json);
}
}
2 changes: 2 additions & 0 deletions ref-exchange/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ mod shadow_actions;
mod unit_lpt_cumulative_infos;
mod pool_limit_info;
mod client_echo_limit;
mod donation;
mod event;

near_sdk::setup_alloc!();

Expand Down
20 changes: 20 additions & 0 deletions ref-exchange/src/multi_fungible_token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,26 @@ impl Contract {
}
}

/// Unregister LP token of given pool for given account.
#[payable]
pub fn mft_unregister(&mut self, token_id: String) {
assert_one_yocto();
let account_id = env::predecessor_account_id();
let prev_storage = env::storage_usage();
match parse_token_id(token_id) {
TokenOrPool::Token(_) => env::panic(ERR111_INVALID_UNREGISTER.as_bytes()),
TokenOrPool::Pool(pool_id) => {
let mut pool = self.pools.get(pool_id).expect(ERR85_NO_POOL);
pool.share_unregister(&account_id);
self.pools.replace(pool_id, &pool);
if prev_storage > env::storage_usage() {
let refund = (prev_storage - env::storage_usage()) as Balance * env::storage_byte_cost();
Promise::new(account_id).transfer(refund);
}
}
}
}

/// Transfer one of internal tokens: LP or balances.
/// `token_id` can either by account of the token or pool number.
#[payable]
Expand Down
2 changes: 1 addition & 1 deletion ref-exchange/src/owner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ impl Contract {
let mut account = self.internal_unwrap_account(&owner_id);
// Note: subtraction and deregistration will be reverted if the promise fails.
account.withdraw(&token_id, amount);
self.internal_save_account(&owner_id, account);
self.accounts.insert(&owner_id, &account.into());
self.internal_send_tokens(&owner_id, &token_id, amount, skip_unwrap_near)
}

Expand Down
9 changes: 9 additions & 0 deletions ref-exchange/src/pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,15 @@ impl Pool {
}
}

pub fn share_unregister(&mut self, account_id: &AccountId) {
match self {
Pool::SimplePool(pool) => pool.share_unregister(account_id),
Pool::StableSwapPool(pool) => pool.share_unregister(account_id),
Pool::RatedSwapPool(pool) => pool.share_unregister(account_id),
Pool::DegenSwapPool(pool) => pool.share_unregister(account_id),
}
}

pub fn predict_add_rated_liquidity(
&self,
amounts: &Vec<Balance>,
Expand Down
7 changes: 7 additions & 0 deletions ref-exchange/src/rated_swap/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,13 @@ impl RatedSwapPool {
self.shares.insert(account_id, &0);
}

/// Unregister account with shares balance of 0.
/// The storage should be refunded to the user.
pub fn share_unregister(&mut self, account_id: &AccountId) {
let shares = self.shares.remove(account_id);
assert!(shares.expect(ERR13_LP_NOT_REGISTERED) == 0, "{}", ERR19_LP_NOT_EMPTY);
}

/// Transfers shares from predecessor to receiver.
pub fn share_transfer(&mut self, sender_id: &AccountId, receiver_id: &AccountId, amount: u128) {
let balance = self.shares.get(&sender_id).expect(ERR13_LP_NOT_REGISTERED);
Expand Down
7 changes: 7 additions & 0 deletions ref-exchange/src/simple_pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,13 @@ impl SimplePool {
self.shares.insert(account_id, &0);
}

/// Unregister account with shares balance of 0.
/// The storage should be refunded to the user.
pub fn share_unregister(&mut self, account_id: &AccountId) {
let shares = self.shares.remove(account_id);
assert!(shares.expect(ERR13_LP_NOT_REGISTERED) == 0, "{}", ERR19_LP_NOT_EMPTY);
}

/// Transfers shares from predecessor to receiver.
pub fn share_transfer(&mut self, sender_id: &AccountId, receiver_id: &AccountId, amount: u128) {
let balance = self.shares.get(&sender_id).expect(ERR13_LP_NOT_REGISTERED);
Expand Down
7 changes: 7 additions & 0 deletions ref-exchange/src/stable_swap/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,13 @@ impl StableSwapPool {
self.shares.insert(account_id, &0);
}

/// Unregister account with shares balance of 0.
/// The storage should be refunded to the user.
pub fn share_unregister(&mut self, account_id: &AccountId) {
let shares = self.shares.remove(account_id);
assert!(shares.expect(ERR13_LP_NOT_REGISTERED) == 0, "{}", ERR19_LP_NOT_EMPTY);
}

/// Transfers shares from predecessor to receiver.
pub fn share_transfer(&mut self, sender_id: &AccountId, receiver_id: &AccountId, amount: u128) {
let balance = self.shares.get(&sender_id).expect(ERR13_LP_NOT_REGISTERED);
Expand Down
138 changes: 138 additions & 0 deletions ref-exchange/tests/test_donation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
use std::collections::HashMap;
use near_sdk::json_types::U128;
use near_sdk::AccountId;
use near_sdk_sim::{call, to_yocto, view};

use crate::common::utils::*;
pub mod common;

#[test]
fn donation_share() {
let (root, _owner, pool, _token1, _token2, _token3) = setup_pool_with_liquidity();
assert_eq!(mft_balance_of(&pool, ":0", &root.account_id()), to_yocto("1"));
assert_eq!(mft_balance_of(&pool, ":0", &pool.account_id()), 0);
assert_eq!(mft_total_supply(&pool, ":0"), to_yocto("1"));
let deposit_before_donation_share = get_storage_state(&pool, to_va(root.account_id.clone())).unwrap().deposit;
call!(
root,
pool.donation_share(
0, None, None
),
deposit = 1
).assert_success();
assert_eq!(deposit_before_donation_share, get_storage_state(&pool, to_va(root.account_id.clone())).unwrap().deposit);
assert_eq!(mft_balance_of(&pool, ":0", &root.account_id()), 0);
assert_eq!(mft_balance_of(&pool, ":0", &pool.account_id()), to_yocto("1"));
assert_eq!(mft_total_supply(&pool, ":0"), to_yocto("1"));

assert!(mft_has_registered(&pool, ":0", root.valid_account_id()));
call!(
root,
pool.mft_unregister(":0".to_string()),
deposit = 1
).assert_success();
assert!(!mft_has_registered(&pool, ":0", root.valid_account_id()));

call!(
root,
pool.add_liquidity(0, vec![U128(to_yocto("10")), U128(to_yocto("20"))], None),
deposit = to_yocto("0.0007")
)
.assert_success();
assert_eq!(mft_balance_of(&pool, ":0", &root.account_id()), 999999999999999999999999);
assert_eq!(mft_balance_of(&pool, ":0", &pool.account_id()), to_yocto("1"));
assert_eq!(mft_total_supply(&pool, ":0"), 1999999999999999999999999u128);
call!(
root,
pool.donation_share(
0, Some(U128(1)), None
),
deposit = 1
).assert_success();
assert_eq!(mft_balance_of(&pool, ":0", &root.account_id()), 999999999999999999999998);
assert_eq!(mft_balance_of(&pool, ":0", &pool.account_id()), to_yocto("1") + 1);
assert_eq!(mft_total_supply(&pool, ":0"), 1999999999999999999999999u128);
let deposit_before_donation_share = get_storage_state(&pool, to_va(root.account_id.clone())).unwrap().deposit.0;
let outcome = call!(
root,
pool.donation_share(
0, None, Some(true)
),
deposit = 1
);
println!("{:#?}", get_logs(&outcome));

assert_eq!(mft_balance_of(&pool, ":0", &root.account_id()), 0);
assert_eq!(mft_balance_of(&pool, ":0", &pool.account_id()), 1999999999999999999999999u128);
assert_eq!(mft_total_supply(&pool, ":0"), 1999999999999999999999999u128);
assert!(deposit_before_donation_share < get_storage_state(&pool, to_va(root.account_id.clone())).unwrap().deposit.0);
}

#[test]
fn donation_token() {
let (root, owner, pool, token1, _token2, _token3) = setup_pool_with_liquidity();
let user = root.create_user("user".to_string(), to_yocto("100"));
mint_and_deposit_token(&user, &token1, &pool, to_yocto("100"));
let balances = view!(pool.get_deposits(to_va(user.account_id.clone())))
.unwrap_json::<HashMap<AccountId, U128>>();
let balances = balances.get(&token1.account_id()).unwrap().0;
assert_eq!(balances, to_yocto("100"));
let balances = view!(pool.get_deposits(to_va(owner.account_id.clone())))
.unwrap_json::<HashMap<AccountId, U128>>();
assert!(balances.is_empty());
call!(
user,
pool.donation_token(
token1.valid_account_id(), None, None
),
deposit = 1
).assert_success();
let balances = view!(pool.get_deposits(to_va(user.account_id.clone())))
.unwrap_json::<HashMap<AccountId, U128>>();
let balances = balances.get(&token1.account_id()).unwrap().0;
assert_eq!(balances, 0);
let balances = view!(pool.get_deposits(to_va(owner.account_id.clone())))
.unwrap_json::<HashMap<AccountId, U128>>();
let balances = balances.get(&token1.account_id()).unwrap().0;
assert_eq!(balances, to_yocto("100"));

let user1 = root.create_user("user1".to_string(), to_yocto("500"));
mint_and_deposit_token(&user1, &token1, &pool, to_yocto("500"));
let balances = view!(pool.get_deposits(to_va(user1.account_id.clone())))
.unwrap_json::<HashMap<AccountId, U128>>();
let balances = balances.get(&token1.account_id()).unwrap().0;
assert_eq!(balances, to_yocto("500"));
call!(
user1,
pool.donation_token(
token1.valid_account_id(), Some(U128(to_yocto("100"))), None
),
deposit = 1
).assert_success();
let balances = view!(pool.get_deposits(to_va(user1.account_id.clone())))
.unwrap_json::<HashMap<AccountId, U128>>();
let balances = balances.get(&token1.account_id()).unwrap().0;
assert_eq!(balances, to_yocto("400"));
let balances = view!(pool.get_deposits(to_va(owner.account_id.clone())))
.unwrap_json::<HashMap<AccountId, U128>>();
let balances = balances.get(&token1.account_id()).unwrap().0;
assert_eq!(balances, to_yocto("200"));

let outcome = call!(
user1,
pool.donation_token(
token1.valid_account_id(), None, Some(true)
),
deposit = 1
);
println!("{:#?}", get_logs(&outcome));

let balances = view!(pool.get_deposits(to_va(user1.account_id.clone())))
.unwrap_json::<HashMap<AccountId, U128>>();
assert!(balances.is_empty());
let balances = view!(pool.get_deposits(to_va(owner.account_id.clone())))
.unwrap_json::<HashMap<AccountId, U128>>();
let balances = balances.get(&token1.account_id()).unwrap().0;
assert_eq!(balances, to_yocto("600"));

}
Binary file modified releases/ref_exchange_release.wasm
Binary file not shown.

0 comments on commit 085aa66

Please sign in to comment.