diff --git a/contract/src/internal.rs b/contract/src/internal.rs index 1fd23c4..5481227 100644 --- a/contract/src/internal.rs +++ b/contract/src/internal.rs @@ -53,7 +53,7 @@ impl NearCLP { from: AccountId, to: AccountId, amount: u128, - // gas: Gas, + deposit: u128, // gas: Gas, ) -> Promise { let gas = env::prepaid_gas(); assert!(gas >= 20 * TGAS, "Not enough gas"); @@ -62,7 +62,7 @@ impl NearCLP { to, amount.into(), token, - util::NEP21_STORAGE_DEPOSIT, + deposit, env::prepaid_gas() / 3, ) } @@ -142,7 +142,13 @@ impl NearCLP { p.reserve -= reserve; p.ynear += near; - self.schedule_nep21_tx(token, env::current_account_id(), recipient, reserve); + self.schedule_nep21_tx( + token, + env::current_account_id(), + recipient, + reserve, + NEP21_STORAGE_DEPOSIT, + ); // TODO: this updated should be done after nep21 transfer self.set_pool(token, p); } @@ -209,8 +215,14 @@ impl NearCLP { p.ynear -= near; // firstly get tokens from the buyer, then send NEAR to recipient - self.schedule_nep21_tx(token, buyer, env::current_account_id(), reserve) - .then(Promise::new(recipient).transfer(near)); + self.schedule_nep21_tx( + token, + buyer, + env::current_account_id(), + reserve, + NEP21_STORAGE_DEPOSIT, + ) + .then(Promise::new(recipient).transfer(near)); // TODO - this should be in a promise. self.set_pool(&token, p); } @@ -278,8 +290,20 @@ impl NearCLP { let caller = env::current_account_id(); // firstly get tokens from buyer, then send to the recipient - self.schedule_nep21_tx(token1, buyer, caller.clone(), token1_in) - .then(self.schedule_nep21_tx(token2, caller, recipient, token2_out)); + self.schedule_nep21_tx( + token1, + buyer, + caller.clone(), + token1_in, + NEP21_STORAGE_DEPOSIT, + ) + .then(self.schedule_nep21_tx( + token2, + caller, + recipient, + token2_out, + NEP21_STORAGE_DEPOSIT, + )); // TODO: make updates after nep21 transfers (together with promise2) self.set_pool(&token1, &p1); self.set_pool(&token2, &p2); diff --git a/contract/src/lib.rs b/contract/src/lib.rs index b39d728..c2eed81 100644 --- a/contract/src/lib.rs +++ b/contract/src/lib.rs @@ -163,13 +163,24 @@ impl NearCLP { /// Increases Near and the Reserve token liquidity. /// The supplied funds must preserve current ratio of the liquidity pool. + /// `transfer_deposit`: amount of yNEAR attached to the NEP21.transfer_from AND + /// deduced from the attached deposit (hence removed from the new pool supply). + /// Usually, on subsequent add_liquidity calls for the given token, we don't need + /// to attach extra deposit for `transfer_from` calls. /// Returns amount of LP Shares is minted for the user. #[payable] - pub fn add_liquidity(&mut self, token: AccountId, max_tokens: U128, min_shares: U128) -> U128 { + pub fn add_liquidity( + &mut self, + token: AccountId, + max_tokens: U128, + min_shares: U128, + transfer_deposit: U128, + ) -> U128 { let mut p = self.must_get_pool(&token); let caller = env::predecessor_account_id(); + let transfer_deposit = u128::from(transfer_deposit); let shares_minted; - let ynear_amount = env::attached_deposit() - NEP21_STORAGE_DEPOSIT; + let ynear_amount = env::attached_deposit() - transfer_deposit; let added_reserve; let max_tokens: Balance = max_tokens.into(); assert!( @@ -234,8 +245,14 @@ impl NearCLP { 0, 5 * TGAS, ); - self.schedule_nep21_tx(&token, caller, env::current_account_id(), added_reserve) - .then(callback); //after that, the callback will check success/failure + self.schedule_nep21_tx( + &token, + caller, + env::current_account_id(), + added_reserve, + transfer_deposit, + ) + .then(callback); //after that, the callback will check success/failure // TODO: // Handling exception is work-in-progress in NEAR runtime @@ -303,6 +320,7 @@ impl NearCLP { env::current_account_id(), caller.clone(), token_amount, + NEP21_STORAGE_DEPOSIT, ) .then(Promise::new(caller).transfer(ynear_amount)); @@ -877,10 +895,16 @@ mod tests { let ynear_deposit = 30 * NDENOM; let token_deposit = 10 * NDENOM; - let ynear_deposit_with_storage = ynear_deposit + NEP21_STORAGE_DEPOSIT; + let ynear_deposit_with_storage = ynear_deposit + 2 * NEP21_STORAGE_DEPOSIT; + let transfer_deposit = U128::from(2 * NEP21_STORAGE_DEPOSIT); ctx.set_deposit(ynear_deposit_with_storage); - c.add_liquidity(t.clone(), token_deposit.into(), ynear_deposit.into()); + c.add_liquidity( + t.clone(), + token_deposit.into(), + ynear_deposit.into(), + transfer_deposit, + ); let mut p = c.pool_info(&t).expect("Pool should exist"); let mut expected_pool = PoolInfo { @@ -909,7 +933,12 @@ mod tests { println!(">> adding liquidity - second time"); - c.add_liquidity(t.clone(), (token_deposit * 10).into(), ynear_deposit.into()); + c.add_liquidity( + t.clone(), + (token_deposit * 10).into(), + ynear_deposit.into(), + transfer_deposit, + ); p = c.pool_info(&t).expect("Pool should exist"); expected_pool = PoolInfo { ynear: (ynear_deposit * 2).into(), @@ -933,9 +962,9 @@ mod tests { fn add_liquidity2_happy_path() { let ynear_deposit = 3 * NDENOM; let token_deposit = 1 * NDENOM + 1; - let ynear_deposit_with_storage = ynear_deposit + NEP21_STORAGE_DEPOSIT; + let transfer_deposit = U128::from(0); - let (ctx, mut c) = _init(ynear_deposit_with_storage); + let (ctx, mut c) = _init(ynear_deposit); let t = ctx.accounts.token1.clone(); let a = ctx.accounts.predecessor.clone(); @@ -950,7 +979,12 @@ mod tests { }; c.pools.insert(&t, &p); - c.add_liquidity(t.clone(), token_deposit.into(), ynear_deposit.into()); + c.add_liquidity( + t.clone(), + token_deposit.into(), + ynear_deposit.into(), + transfer_deposit, + ); let p_info = c.pool_info(&t).expect("Pool should exist"); let expected_pool = PoolInfo { diff --git a/contract/src/util.rs b/contract/src/util.rs index 4fa34ab..c563886 100644 --- a/contract/src/util.rs +++ b/contract/src/util.rs @@ -13,7 +13,7 @@ pub const TGAS: Gas = 1_000_000_000_000; pub const MAX_GAS: Gas = 200 * TGAS; /// nep21 may require NEAR deposit for storage to create a new balance -pub const NEP21_STORAGE_DEPOSIT: u128 = 4 * NDENOM / 100; //0.04 NEAR +pub const NEP21_STORAGE_DEPOSIT: u128 = 5 * NDENOM / 100; //0.05 NEAR // TODO: should we make it customizable? /// Price per 1 byte of storage from mainnet genesis config. 100e18 diff --git a/contract/tests/simulation_test.rs b/contract/tests/simulation_test.rs index 82b78f1..4bd1636 100644 --- a/contract/tests/simulation_test.rs +++ b/contract/tests/simulation_test.rs @@ -119,7 +119,6 @@ fn add_liquidity( show_nep21_bal(r, &token.account_id, &liquidity_provider.account_id); - //add_liquidity call( r, &liquidity_provider, @@ -127,7 +126,8 @@ fn add_liquidity( "add_liquidity", &json!({"token": token.account_id, "max_tokens": token_amount.to_string(), - "min_shares": near_amount.to_string()}), + "min_shares": near_amount.to_string(), + "transfer_deposit": NEP21_STORAGE_DEPOSIT.to_string()}), (near_amount + NEP21_STORAGE_DEPOSIT).into(), //send NEAR ); diff --git a/webapp/src/services/near-nep21-util.js b/webapp/src/services/near-nep21-util.js index c9a61ec..59e4823 100644 --- a/webapp/src/services/near-nep21-util.js +++ b/webapp/src/services/near-nep21-util.js @@ -3,7 +3,7 @@ import { Contract} from 'near-api-js' const e22 = '0'.repeat(22); const maxGas = '300000000000000'; const attach60NearCents = '6' + e22; -const nep21AllowanceFee = '4' + e22; +const nep21AllowanceFee = '5' + e22; const NDENOM = 1e24; export async function getBalanceNEP( contractName ) { @@ -315,7 +315,6 @@ export async function swapFromOut( tokenIN, tokenOUT ) { maxGas, attach60NearCents ); - } else { console.error("Error: Token type error"); @@ -323,17 +322,17 @@ export async function swapFromOut( tokenIN, tokenOUT ) { } } -export async function addLiquiduty( tokenDetails, maxTokenAmount, minSharesAmount ) { - await window.contract.add_liquidity( { token: tokenDetails.address, - max_tokens: maxTokenAmount, - min_shares: minSharesAmount}, - maxGas, - attach60NearCents - ); +export function addLiquidity( tokenDetails, maxTokenAmount, minSharesAmount, ynear, transferDeposit ) { + return window.contract.add_liquidity( { token: tokenDetails.address, + max_tokens: maxTokenAmount, + min_shares: minSharesAmount, + transfer_deposit: transferDeposit}, + maxGas, + ynear); } // returns true if pool already exists -export async function createPool( tokenDetails, maxTokenAmount, minSharesAmount ) { +export async function createPool( tokenDetails, tokenAmount, ynearAmount ) { const info = await window.contract.pool_info( { token: tokenDetails.address} ); if(info !== null) { @@ -341,8 +340,7 @@ export async function createPool( tokenDetails, maxTokenAmount, minSharesAmount return true; } await window.contract.create_pool( { token: tokenDetails.address }); - - await addLiquiduty( tokenDetails.address, maxTokenAmount, minSharesAmount); + await addLiquidity( tokenDetails.address, tokenAmount, ynearAmount, ynearAmount, nep21AllowanceFee); return false; }