diff --git a/ref-exchange/src/account_deposit.rs b/ref-exchange/src/account_deposit.rs index 66c07e7..1fe9e5a 100644 --- a/ref-exchange/src/account_deposit.rs +++ b/ref-exchange/src/account_deposit.rs @@ -5,29 +5,98 @@ use std::convert::TryInto; use near_sdk::borsh::{self, BorshDeserialize, BorshSerialize}; use near_sdk::json_types::{ValidAccountId, U128}; -use near_sdk::{assert_one_yocto, env, near_bindgen, AccountId, Balance, PromiseResult}; +use near_sdk::{ + assert_one_yocto, env, near_bindgen, AccountId, Balance, PromiseResult, StorageUsage, +}; use crate::utils::{ext_fungible_token, ext_self, GAS_FOR_FT_TRANSFER}; use crate::*; -const MAX_ACCOUNT_LENGTH: u128 = 64; -const MIN_ACCOUNT_DEPOSIT_LENGTH: u128 = MAX_ACCOUNT_LENGTH + 16 + 4; +const U128_STORAGE: StorageUsage = 16; +/// bytes length of u64 values +const U64_STORAGE: StorageUsage = 8; +/// bytes length of u32 values. Used in length operations +const U32_STORAGE: StorageUsage = 4; +/// max length of account id is 64 bytes. We charge per byte. +const ACC_ID_STORAGE: StorageUsage = 64; + +// ACC_ID: the Contract accounts map +// + U128_STORAGE: near_amount storage +// + U32_STORAGE: tokens HashMap length +// + U64_STORAGE: storage_used +pub const INIT_ACCOUNT_STORAGE: StorageUsage = + ACC_ID_STORAGE + U128_STORAGE + U32_STORAGE + 2 * U64_STORAGE; + +// NEAR native token. This is not a valid token ID. HACK: NEAR is a native token, we use the +// empty string we use it to reference not existing near account. +// pub const NEAR: AccountId = "".to_string(); + +#[derive(BorshDeserialize, BorshSerialize)] +pub enum AccountDeposit { + V2(AccountDepositV2), +} + +impl From for AccountDepositV2 { + fn from(account: AccountDeposit) -> Self { + match account { + AccountDeposit::V2(a) => { + if a.storage_used > 0 { + return a; + } + // migrate from V1 + a.storage_used = U64_STORAGE; + a + } + } + } +} /// Account deposits information and storage cost. +/// Legacy version #[derive(BorshSerialize, BorshDeserialize, Default)] #[cfg_attr(feature = "test", derive(Clone))] -pub struct AccountDeposit { - /// Native amount sent to the exchange. - /// Used for storage now, but in future can be used for trading as well. - pub amount: Balance, +pub struct AccountDepositV1 { + /// NEAR sent to the exchange. + /// Used for storage and trading. + pub near_amount: Balance, /// Amounts of various tokens in this account. pub tokens: HashMap, } -impl AccountDeposit { +/// Account deposits information and storage cost. +#[derive(BorshSerialize, BorshDeserialize, Default)] +#[cfg_attr(feature = "test", derive(Clone))] +pub struct AccountDepositV2 { + /// NEAR sent to the exchange. + /// Used for storage and trading. + pub near_amount: Balance, + /// Amounts of various tokens in this account. + pub tokens: HashMap, + pub storage_used: StorageUsage, +} + +impl From for AccountDeposit { + fn from(a: AccountDepositV2) -> Self { + AccountDeposit::V2(a) + } +} + +impl AccountDepositV2 { + pub fn new(account_id: &AccountId, near_amount: Balance) -> Self { + Self { + near_amount, + tokens: HashMap::default(), + // Here we manually compute the initial storage size of account deposit. + storage_used: U64_STORAGE, + } + } + /// Adds amount to the balance of given token while checking that storage is covered. pub(crate) fn add(&mut self, token: &AccountId, amount: Balance) { - if let Some(x) = self.tokens.get_mut(token) { + if *token == "" { + // We use empty string to represent NEAR + self.near_amount += amount; + } else if let Some(x) = self.tokens.get_mut(token) { *x = *x + amount; } else { self.tokens.insert(token.clone(), amount); @@ -38,38 +107,50 @@ impl AccountDeposit { /// Subtract from `token` balance. /// Panics if `amount` is bigger than the current balance. pub(crate) fn sub(&mut self, token: &AccountId, amount: Balance) { + if *token == "" { + // We use empty string to represent NEAR + self.near_amount -= amount; + self.assert_storage_usage(); + return; + } let value = *self.tokens.get(token).expect(ERR21_TOKEN_NOT_REG); assert!(value >= amount, "{}", ERR22_NOT_ENOUGH_TOKENS); self.tokens.insert(token.clone(), value - amount); } - /// Returns amount of $NEAR necessary to cover storage used by this data structure. + /// Returns amount of $NEAR necessary to cover storage used by account referenced to this structure. pub fn storage_usage(&self) -> Balance { - (MIN_ACCOUNT_DEPOSIT_LENGTH + self.tokens.len() as u128 * (MAX_ACCOUNT_LENGTH + 16)) - * env::storage_byte_cost() + let s = self.storage_used + + INIT_ACCOUNT_STORAGE // empty account storage + + (ACC_ID_STORAGE + U64_STORAGE) * self.tokens.len() as u64; // self.tokens storage + return s as Balance * env::storage_byte_cost(); } - /// Returns how much NEAR is available for storage. - pub fn storage_available(&self) -> Balance { - self.amount - self.storage_usage() + /// Returns how much NEAR is available for storage and swaps. + #[inline] + pub(crate) fn storage_available(&self) -> Balance { + self.near_amount - self.storage_usage() } /// Asserts there is sufficient amount of $NEAR to cover storage usage. + #[inline] pub fn assert_storage_usage(&self) { assert!( - self.storage_usage() <= self.amount, + self.storage_usage() <= self.near_amount, "{}", ERR11_INSUFFICIENT_STORAGE ); } - /// Returns minimal account deposit storage usage possible. - pub fn min_storage_usage() -> Balance { - MIN_ACCOUNT_DEPOSIT_LENGTH * env::storage_byte_cost() + /// Updates the account storage usage. + /// Panics if there is not enought $NEAR to cover storage usage. + pub(crate) fn update_storage(&mut self, tx_start_storage: StorageUsage) { + self.storage_used += env::storage_usage() - tx_start_storage; + self.assert_storage_usage(); } - /// Registers given token and set balance to 0. - /// Fails if not enough amount to cover new storage usage. + /// Registers given `token_id` and set balance to 0. + /// Panics if there is not enought $NEAR to cover storage usage. pub(crate) fn register(&mut self, token_ids: &Vec) { for token_id in token_ids { let t = token_id.as_ref(); @@ -90,24 +171,35 @@ impl AccountDeposit { #[near_bindgen] impl Contract { + /// Deposits attached NEAR into predecessor account deposits. The deposited near will be used + /// for trades and for storage. Predecessor account must be registered. Panics otherwise. + /// NOTE: this is a simplified and more direct version of `storage_deposit` function. + #[payable] + pub fn deposit_near(&mut self) { + let sender_id = env::predecessor_account_id(); + let mut acc = self.get_account(&sender_id); + acc.near_amount += env::attached_deposit(); + self.accounts.insert(&sender_id, &acc.into()); + } + /// Registers given token in the user's account deposit. /// Fails if not enough balance on this account to cover storage. pub fn register_tokens(&mut self, token_ids: Vec) { let sender_id = env::predecessor_account_id(); - let mut deposits = self.get_account_deposits(&sender_id); - deposits.register(&token_ids); - self.deposited_amounts.insert(&sender_id, &deposits); + let mut acc = self.get_account(&sender_id); + acc.register(&token_ids); + self.accounts.insert(&sender_id, &acc.into()); } /// Unregister given token from user's account deposit. /// Panics if the balance of any given token is non 0. pub fn unregister_tokens(&mut self, token_ids: Vec) { let sender_id = env::predecessor_account_id(); - let mut deposits = self.get_account_deposits(&sender_id); + let mut deposits = self.get_account(&sender_id); for token_id in token_ids { deposits.unregister(token_id.as_ref()); } - self.deposited_amounts.insert(&sender_id, &deposits); + self.accounts.insert(&sender_id, &deposits.into()); } /// Withdraws given token from the deposits of given user. @@ -119,13 +211,13 @@ impl Contract { let token_id: AccountId = token_id.into(); let amount: u128 = amount.into(); let sender_id = env::predecessor_account_id(); - let mut deposits = self.get_account_deposits(&sender_id); + let mut deposits = self.get_account(&sender_id); // Note: subtraction and deregistration will be reverted if the promise fails. deposits.sub(&token_id, amount); if unregister == Some(true) { deposits.unregister(&token_id); } - self.deposited_amounts.insert(&sender_id, &deposits); + self.accounts.insert(&sender_id, &deposits.into()); ext_fungible_token::ft_transfer( sender_id.clone().try_into().unwrap(), amount.into(), @@ -162,9 +254,9 @@ impl Contract { PromiseResult::Successful(_) => {} PromiseResult::Failed => { // This reverts the changes from withdraw function. - let mut deposits = self.get_account_deposits(&sender_id); + let mut deposits = self.get_account(&sender_id); deposits.add(&token_id, amount.0); - self.deposited_amounts.insert(&sender_id, &deposits); + self.accounts.insert(&sender_id, &deposits.into()); } }; } @@ -174,10 +266,14 @@ impl Contract { /// Registers account in deposited amounts with given amount of $NEAR. /// If account already exists, adds amount to it. /// This should be used when it's known that storage is prepaid. - pub(crate) fn internal_register_account(&mut self, account_id: &AccountId, amount: Balance) { - let mut deposit_amount = self.deposited_amounts.get(&account_id).unwrap_or_default(); - deposit_amount.amount += amount; - self.deposited_amounts.insert(&account_id, &deposit_amount); + pub(crate) fn register_account(&mut self, account_id: &AccountId, amount: Balance) { + let acc = if let Some(mut account_deposit) = self.accounts.get(&account_id) { + account_deposit.near_amount += amount; + account_deposit + } else { + AccountDepositV2::new(account_id, amount) + }; + self.accounts.insert(&account_id, &acc); } /// Record deposit of some number of tokens to this contract. @@ -188,34 +284,49 @@ impl Contract { token_id: &AccountId, amount: Balance, ) { - let mut account_deposit = self.get_account_deposits(sender_id); + let mut acc = self.get_account(sender_id); assert!( - self.whitelisted_tokens.contains(token_id) - || account_deposit.tokens.contains_key(token_id), + self.whitelisted_tokens.contains(token_id) || acc.tokens.contains_key(token_id), "{}", ERR12_TOKEN_NOT_WHITELISTED ); - account_deposit.add(token_id, amount); - self.deposited_amounts.insert(sender_id, &account_deposit); + acc.add(token_id, amount); + self.accounts.insert(sender_id, &acc.into()); } // Returns `from` AccountDeposit. #[inline] - pub(crate) fn get_account_deposits(&self, from: &AccountId) -> AccountDeposit { - self.deposited_amounts + pub(crate) fn get_account(&self, from: &AccountId) -> AccountDepositV2 { + self.accounts .get(from) .expect(ERR10_ACC_NOT_REGISTERED) + .into() } - /// Returns current balance of given token for given user. If there is nothing recorded, returns 0. - pub(crate) fn internal_get_deposit( + pub(crate) fn get_account_option(&self, from: &AccountId) -> Option { + // let key = ("d".to_owned() + from).into_bytes(); + // let data = env::storage_read(&key); + // if data == None { + // return None; + // } + // let Some(data) = data; + // AccountDepositV1::Dese + // borsh::de:: + + self.accounts.get(from).and_then(|a| a.into()) + } + + /// Returns current balance of given token for given user. If token_id == "" then returns NEAR (native) + /// balance. If there is nothing recorded, returns 0. + pub(crate) fn get_deposit_balance( &self, sender_id: &AccountId, token_id: &AccountId, ) -> Balance { - self.deposited_amounts - .get(sender_id) - .and_then(|d| d.tokens.get(token_id).cloned()) - .unwrap_or_default() + let acc = self.get_account(sender_id); + if token_id == "" { + return acc.near_amount; + } + *acc.tokens.get(token_id).unwrap_or(&0) } } diff --git a/ref-exchange/src/errors.rs b/ref-exchange/src/errors.rs index bcfa910..9142e0d 100644 --- a/ref-exchange/src/errors.rs +++ b/ref-exchange/src/errors.rs @@ -5,7 +5,7 @@ pub const ERR11_INSUFFICIENT_STORAGE: &str = "E11: insufficient $NEAR storage de pub const ERR12_TOKEN_NOT_WHITELISTED: &str = "E12: token not whitelisted"; // Account Deposits // - +// TODO: change type to avoid assert!(..., "{}", ERR...). Maybe using raw strings? r#""# pub const ERR21_TOKEN_NOT_REG: &str = "E21: token not registered"; pub const ERR22_NOT_ENOUGH_TOKENS: &str = "E22: not enough tokens in deposit"; // pub const ERR23_NOT_ENOUGH_NEAR: &str = "E23: not enough NEAR in deposit"; diff --git a/ref-exchange/src/legacy.rs b/ref-exchange/src/legacy.rs index 33dc7c6..c51871d 100644 --- a/ref-exchange/src/legacy.rs +++ b/ref-exchange/src/legacy.rs @@ -4,7 +4,7 @@ use near_sdk::borsh::{self, BorshDeserialize, BorshSerialize}; use near_sdk::collections::{LookupMap, Vector}; use near_sdk::AccountId; -use crate::account_deposit::AccountDeposit; +use crate::account_deposit::AccountDepositV2; use crate::pool::Pool; /// Version before whitelisted tokens collection. @@ -19,5 +19,5 @@ pub struct ContractV1 { /// List of all the pools. pub pools: Vector, /// Balances of deposited tokens for each account. - pub deposited_amounts: LookupMap, + pub deposited_amounts: LookupMap, } diff --git a/ref-exchange/src/lib.rs b/ref-exchange/src/lib.rs index c8c5182..6d36ddf 100644 --- a/ref-exchange/src/lib.rs +++ b/ref-exchange/src/lib.rs @@ -6,9 +6,11 @@ use near_contract_standards::storage_management::{ use near_sdk::borsh::{self, BorshDeserialize, BorshSerialize}; use near_sdk::collections::{LookupMap, UnorderedSet, Vector}; use near_sdk::json_types::{ValidAccountId, U128}; -use near_sdk::{assert_one_yocto, env, log, near_bindgen, AccountId, PanicOnDefault, Promise}; +use near_sdk::{ + assert_one_yocto, env, log, near_bindgen, AccountId, PanicOnDefault, Promise, StorageUsage, +}; -use crate::account_deposit::AccountDeposit; +use crate::account_deposit::{AccountDeposit, AccountDepositV1, INIT_ACCOUNT_STORAGE}; pub use crate::action::*; use crate::errors::*; use crate::pool::Pool; @@ -42,7 +44,7 @@ pub struct Contract { /// List of all the pools. pools: Vector, /// Balances of deposited tokens for each account. - deposited_amounts: LookupMap, + accounts: LookupMap, /// Set of whitelisted tokens by "owner". whitelisted_tokens: UnorderedSet, } @@ -56,15 +58,19 @@ impl Contract { exchange_fee, referral_fee, pools: Vector::new(b"p".to_vec()), - deposited_amounts: LookupMap::new(b"d".to_vec()), + accounts: LookupMap::new(b"d".to_vec()), whitelisted_tokens: UnorderedSet::new(b"w".to_vec()), } } - /// Adds new "Simple Pool" with given tokens and given fee. - /// Attached NEAR should be enough to cover the added storage. + /// Adds new "Simple Pool" with given tokens and given fee. The effective pool fee is + /// `fee + exchange_fee + referralp_fee`. + /// This function doesn't set the initial price nor adds any liquidity to the pool. You must call the + /// `add_liquidity` for that. + /// Deposited NEAR must be enough to cover the added storage. #[payable] pub fn add_simple_pool(&mut self, tokens: Vec, fee: u32) -> u64 { + assert_one_yocto(); check_token_duplicates(&tokens); self.internal_add_pool(Pool::SimplePool(SimplePool::new( self.pools.len() as u32, @@ -101,7 +107,7 @@ impl Contract { U128(prev_amount.expect("ERR_AT_LEAST_ONE_SWAP")) } - /// Add liquidity from already deposited amounts to given pool. + /// Add liquidity from already deposited amounts to the given pool. #[payable] pub fn add_liquidity( &mut self, @@ -110,6 +116,7 @@ impl Contract { min_amounts: Option>, ) { assert_one_yocto(); + let start_storage = env::storage_usage(); let sender_id = env::predecessor_account_id(); let mut amounts: Vec = amounts.into_iter().map(|amount| amount.into()).collect(); let mut pool = self.pools.get(pool_id).expect("ERR_NO_POOL"); @@ -121,20 +128,23 @@ impl Contract { assert!(amount >= &min_amount.0, "ERR_MIN_AMOUNT"); } } - let mut deposits = self.deposited_amounts.get(&sender_id).unwrap_or_default(); + let mut acc = self.get_account(&sender_id); let tokens = pool.tokens(); - // Subtract updated amounts from deposits. This will fail if there is not enough funds for any of the tokens. + // Subtract updated amounts from deposits. Fails if there is not enough funds for any of the tokens. for i in 0..tokens.len() { - deposits.sub(&tokens[i], amounts[i]); + acc.sub(&tokens[i], amounts[i]); } - self.deposited_amounts.insert(&sender_id, &deposits); self.pools.replace(pool_id, &pool); + // Can create a new shares record in a pool + acc.update_storage(start_storage); + self.accounts.insert(&sender_id, &acc.into()); } - /// Remove liquidity from the pool into general pool of liquidity. + /// Remove liquidity from the pool and transfer it into account deposit. #[payable] pub fn remove_liquidity(&mut self, pool_id: u64, shares: U128, min_amounts: Vec) { assert_one_yocto(); + let start_storage = env::storage_usage(); let sender_id = env::predecessor_account_id(); let mut pool = self.pools.get(pool_id).expect("ERR_NO_POOL"); let amounts = pool.remove_liquidity( @@ -147,34 +157,35 @@ impl Contract { ); self.pools.replace(pool_id, &pool); let tokens = pool.tokens(); - let mut deposits = self.deposited_amounts.get(&sender_id).unwrap_or_default(); + let mut acc = self.get_account(&&sender_id); for i in 0..tokens.len() { - deposits.add(&tokens[i], amounts[i]); + acc.add(&tokens[i], amounts[i]); } - self.deposited_amounts.insert(&sender_id, &deposits); + // Can remove shares record in a pool + acc.update_storage(start_storage); + self.accounts.insert(&sender_id, &acc.into()); } } /// Internal methods implementation. impl Contract { + /// loads the accoutn from self.accounts, updates the storage used and asserts that there is enough NEAR + /// balance to cover storage cost. + fn update_acc_storage(&mut self, tx_start_storage: StorageUsage) { + let from = env::predecessor_account_id(); + let mut acc = self.get_account(&from); + acc.update_storage(tx_start_storage); + self.accounts.insert(&from, &acc.into()); + } + /// Adds given pool to the list and returns it's id. /// If there is not enough attached balance to cover storage, fails. /// If too much attached - refunds it back. fn internal_add_pool(&mut self, pool: Pool) -> u64 { - let prev_storage = env::storage_usage(); + let start_storage = env::storage_usage(); let id = self.pools.len() as u64; self.pools.push(&pool); - - // Check how much storage cost and refund the left over back. - let storage_cost = (env::storage_usage() - prev_storage) as u128 * env::storage_byte_cost(); - assert!( - storage_cost <= env::attached_deposit(), - "ERR_STORAGE_DEPOSIT" - ); - let refund = env::attached_deposit() - storage_cost; - if refund > 0 { - Promise::new(env::predecessor_account_id()).transfer(refund); - } + self.update_acc_storage(start_storage); id } @@ -190,8 +201,9 @@ impl Contract { min_amount_out: u128, referral_id: &Option, ) -> u128 { - let mut deposits = self.deposited_amounts.get(&sender_id).unwrap_or_default(); - deposits.sub(token_in, amount_in); + let start_storage = env::storage_usage(); + let mut acc = self.get_account(&sender_id); + acc.sub(token_in, amount_in); // NOTE: panics when there is not enough `token_in` deposit. let mut pool = self.pools.get(pool_id).expect("ERR_NO_POOL"); let amount_out = pool.swap( token_in, @@ -201,9 +213,15 @@ impl Contract { &self.owner_id, referral_id, ); - deposits.add(token_out, amount_out); - self.deposited_amounts.insert(&sender_id, &deposits); + acc.add(token_out, amount_out); + self.accounts.insert(&sender_id, &acc.into()); self.pools.replace(pool_id, &pool); + // NOTE: this can cause changes in the deposits which increases an account storage (eg, + // if user doesn't have `token_out` in AccountDepoist, then a new record will be created). + // This is not a problem, because we compute the `AccountDepoist` storage consumption + // separaterly, hence we must do this update. + acc.update_storage(start_storage); + self.accounts.insert(&sender_id, &acc.into()); amount_out } } @@ -370,6 +388,18 @@ mod tests { None, ); assert_eq!(contract.get_deposit(accounts(3), accounts(1)).0, 0); + + // must work with NEAR deposits + testing_env!(context + .predecessor_account_id(accounts(3)) + .attached_deposit(100) + .build()); + assert_eq!( + contract + .get_deposit(accounts(3), "".to_string().try_into().unwrap()) + .0, + 100 + ); } /// Test liquidity management. diff --git a/ref-exchange/src/owner.rs b/ref-exchange/src/owner.rs index 23f57c3..6d174fb 100644 --- a/ref-exchange/src/owner.rs +++ b/ref-exchange/src/owner.rs @@ -6,7 +6,7 @@ use crate::legacy::ContractV1; use crate::utils::{GAS_FOR_DEPLOY_CALL, GAS_FOR_UPGRADE_CALL}; #[near_bindgen] -impl Contract { +impl ContractV1 { /// Change owner. Only can be called by owner. pub fn set_owner(&mut self, owner_id: ValidAccountId) { self.assert_owner(); @@ -64,7 +64,7 @@ impl Contract { exchange_fee: contract_v1.exchange_fee, referral_fee: contract_v1.referral_fee, pools: contract_v1.pools, - deposited_amounts: contract_v1.deposited_amounts, + accounts: contract_v1.deposited_amounts, whitelisted_tokens: UnorderedSet::new(b"w".to_vec()), } } diff --git a/ref-exchange/src/simple_pool.rs b/ref-exchange/src/simple_pool.rs index bda6bb2..9217268 100644 --- a/ref-exchange/src/simple_pool.rs +++ b/ref-exchange/src/simple_pool.rs @@ -316,7 +316,7 @@ mod tests { accounts(2).as_ref(), 1, accounts(3).as_ref(), - Some(accounts(4).as_ref().clone()), + &Some(accounts(4).as_ref().clone()), ); assert_eq!( pool.share_balances(accounts(0).as_ref()), @@ -348,7 +348,7 @@ mod tests { accounts(2).as_ref(), 1, accounts(3).as_ref(), - Some(accounts(4).as_ref().clone()), + &Some(accounts(4).as_ref().clone()), ); assert_eq!( pool.share_balances(accounts(0).as_ref()), diff --git a/ref-exchange/src/storage_impl.rs b/ref-exchange/src/storage_impl.rs index cd4b952..45bf223 100644 --- a/ref-exchange/src/storage_impl.rs +++ b/ref-exchange/src/storage_impl.rs @@ -20,20 +20,20 @@ impl StorageManagement for Contract { } if registration_only { // Registration only setups the account but doesn't leave space for tokens. - if self.deposited_amounts.contains_key(&account_id) { + if self.accounts.contains_key(&account_id) { log!("ERR_ACC_REGISTERED"); if amount > 0 { Promise::new(env::predecessor_account_id()).transfer(amount); } } else { - self.internal_register_account(&account_id, min_balance); + self.register_account(&account_id, min_balance); let refund = amount - min_balance; if refund > 0 { Promise::new(env::predecessor_account_id()).transfer(refund); } } } else { - self.internal_register_account(&account_id, amount); + self.register_account(&account_id, amount); } self.storage_balance_of(account_id.try_into().unwrap()) .unwrap() @@ -43,7 +43,7 @@ impl StorageManagement for Contract { fn storage_withdraw(&mut self, amount: Option) -> StorageBalance { assert_one_yocto(); let account_id = env::predecessor_account_id(); - let account_deposit = self.get_account_deposits(&account_id); + let account_deposit = self.get_account(&account_id); let available = account_deposit.storage_available(); let amount = amount.map(|a| a.0).unwrap_or(available); assert!(amount <= available, "ERR_STORAGE_WITHDRAW_TOO_MUCH"); @@ -57,14 +57,14 @@ impl StorageManagement for Contract { fn storage_unregister(&mut self, force: Option) -> bool { assert_one_yocto(); let account_id = env::predecessor_account_id(); - if let Some(account_deposit) = self.deposited_amounts.get(&account_id) { + if let Some(account_deposit) = self.accounts.get(&account_id) { // TODO: figure out force option logic. assert!( account_deposit.tokens.is_empty(), "ERR_STORAGE_UNREGISTER_TOKENS_NOT_EMPTY" ); - self.deposited_amounts.remove(&account_id); - Promise::new(account_id.clone()).transfer(account_deposit.amount); + self.accounts.remove(&account_id); + Promise::new(account_id.clone()).transfer(account_deposit.near_amount); true } else { false @@ -73,16 +73,16 @@ impl StorageManagement for Contract { fn storage_balance_bounds(&self) -> StorageBalanceBounds { StorageBalanceBounds { - min: AccountDeposit::min_storage_usage().into(), + min: (INIT_ACCOUNT_STORAGE as u128 * env::storage_byte_cost()).into(), max: None, } } fn storage_balance_of(&self, account_id: ValidAccountId) -> Option { - self.deposited_amounts + self.accounts .get(account_id.as_ref()) .map(|deposits| StorageBalance { - total: U128(deposits.amount), + total: U128(deposits.near_amount), available: U128(deposits.storage_available()), }) } diff --git a/ref-exchange/src/views.rs b/ref-exchange/src/views.rs index 8637c3f..ef037c7 100644 --- a/ref-exchange/src/views.rs +++ b/ref-exchange/src/views.rs @@ -89,7 +89,7 @@ impl Contract { /// Returns balances of the deposits for given user outside of any pools. /// Returns empty list if no tokens deposited. pub fn get_deposits(&self, account_id: ValidAccountId) -> HashMap { - self.deposited_amounts + self.accounts .get(account_id.as_ref()) .map(|d| { d.tokens @@ -102,7 +102,7 @@ impl Contract { /// Returns balance of the deposit for given user outside of any pools. pub fn get_deposit(&self, account_id: ValidAccountId, token_id: ValidAccountId) -> U128 { - self.internal_get_deposit(account_id.as_ref(), token_id.as_ref()) + self.get_deposit_balance(account_id.as_ref(), token_id.as_ref()) .into() } @@ -126,7 +126,7 @@ impl Contract { /// Get specific user whitelisted tokens. pub fn get_user_whitelisted_tokens(&self, account_id: &AccountId) -> Vec { - self.deposited_amounts + self.accounts .get(&account_id) .map(|d| d.tokens.keys().cloned().collect()) .unwrap_or_default() diff --git a/res/ref_exchange_local.wasm b/res/ref_exchange_local.wasm index c74ec34..3fb773d 100755 Binary files a/res/ref_exchange_local.wasm and b/res/ref_exchange_local.wasm differ