diff --git a/Cargo.toml b/Cargo.toml index b921d39..24f3800 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] edition = "2018" name = "usn" -version = "2.3.2" +version = "2.3.3" [lib] crate-type = ["cdylib"] diff --git a/src/lib.rs b/src/lib.rs index 5b9f851..8a1c1fb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,7 +27,7 @@ use oracle::{ExchangeRate, Oracle, PriceData}; use std::fmt::Debug; use crate::ft::FungibleTokenFreeStorage; -use stable::{usdt_id, AssetInfo, CommissionRate, OldStableTreasury, StableTreasury}; +use stable::{usdt_id, AssetInfo, CommissionRate, StableTreasury}; uint::construct_uint!( pub struct U256(4); @@ -366,125 +366,8 @@ impl Contract { #[init(ignore_state)] #[private] pub fn migrate() -> Self { - use near_sdk::Timestamp; - - #[derive(BorshSerialize, BorshDeserialize)] - struct ExchangeRate { - multiplier: u128, - decimals: u8, - timestamp: Timestamp, - recency_duration: Timestamp, - } - #[derive(BorshSerialize, BorshDeserialize)] - struct ExchangeRates { - pub current: ExchangeRate, - pub smooth: ExchangeRate, - } - - #[derive(BorshDeserialize, BorshSerialize)] - struct ExponentialSpreadParams { - pub min: f64, - pub max: f64, - pub scaler: f64, - } - - #[derive(BorshDeserialize, BorshSerialize)] - enum Spread { - Fixed(Balance), - Exponential(ExponentialSpreadParams), - } - - #[derive(BorshDeserialize, BorshSerialize)] - struct CacheItem { - pub timestamp: Timestamp, - pub value: f64, - pub smoothed_value: f64, - pub n: u8, - } - - #[derive(BorshDeserialize, BorshSerialize)] - struct IntervalCache { - pub items: Vec, - } - - #[derive(BorshDeserialize, BorshSerialize)] - struct TreasuryData { - pub cache: IntervalCache, - } - - #[derive(BorshDeserialize, BorshSerialize)] - struct ExchangeRateValue { - multiplier: U128, - decimals: u8, - } - - #[derive(BorshDeserialize, BorshSerialize)] - struct MinMaxRate { - max_previous: Option, - max_current: Option, - min_previous: Option, - min_current: Option, - timestamp: Timestamp, - } - - #[derive(BorshDeserialize, BorshSerialize)] - struct VolumeCacheItem { - usn: U128, - near: U128, - timestamp: Timestamp, - } - - #[derive(BorshDeserialize, BorshSerialize)] - struct VolumeCache { - time_slot: Timestamp, - max_age: Timestamp, - sum_usn: U128, - sum_near: U128, - items: Vec, - } - - #[derive(BorshDeserialize, BorshSerialize)] - struct VolumeHistory { - pub one_hour: VolumeCache, - pub five_min: VolumeCache, - } - - #[derive(BorshDeserialize, BorshSerialize)] - struct PrevContract { - owner_id: AccountId, - proposed_owner_id: AccountId, - guardians: UnorderedSet, - token: FungibleTokenFreeStorage, - metadata: LazyOption, - black_list: LookupMap, - status: ContractStatus, - oracle: Oracle, - spread: Spread, - commission: CommissionV1, - treasury: LazyOption, - usn2near: VolumeHistory, - near2usn: VolumeHistory, - best_rate: MinMaxRate, - stable_treasury: OldStableTreasury, - } - - let mut prev: PrevContract = env::state_read().expect("Contract is not initialized"); - - Self { - owner_id: prev.owner_id, - proposed_owner_id: prev.proposed_owner_id, - guardians: prev.guardians, - token: prev.token, - metadata: prev.metadata, - black_list: prev.black_list, - status: prev.status, - commission: prev.commission, - stable_treasury: StableTreasury::from_old( - &mut prev.stable_treasury, - StorageKey::StableTreasury, - ), - oracle: prev.oracle, - } + let prev: Contract = env::state_read().expect("Contract is not initialized"); + prev } fn abort_if_pause(&self) { @@ -806,6 +689,13 @@ impl Contract { self.token.internal_deposit(&account_id, amount); event::emit::ft_mint(&account_id, amount, None); } + + #[payable] + pub fn transfer_near(&mut self, account_id: AccountId, amount: U128) -> Promise { + assert_one_yocto(); + self.assert_owner(); + Promise::new(account_id).transfer(amount.into()) + } } #[cfg(all(test, not(target_arch = "wasm32")))] diff --git a/src/stable.rs b/src/stable.rs index 778f1d5..3f589a9 100644 --- a/src/stable.rs +++ b/src/stable.rs @@ -50,13 +50,6 @@ impl Default for CommissionRate { } } -#[derive(BorshDeserialize, BorshSerialize)] -pub struct OldAssetInfo { - decimals: u8, - commission: U128, - status: AssetStatus, -} - #[derive(BorshDeserialize, BorshSerialize, Serialize, Deserialize, Debug)] #[serde(crate = "near_sdk::serde")] pub struct AssetInfo { @@ -87,20 +80,6 @@ impl AssetInfo { } } -fn copy_asset_info(old_asset_info: &OldAssetInfo) -> AssetInfo { - AssetInfo { - decimals: old_asset_info.decimals, - status: old_asset_info.status.clone(), - commission: old_asset_info.commission, - commission_rate: CommissionRate::default(), - } -} - -#[derive(BorshDeserialize, BorshSerialize)] -pub struct OldStableTreasury { - stable_token: UnorderedMap, -} - #[derive(BorshDeserialize, BorshSerialize)] pub struct StableTreasury { assets: UnorderedMap, @@ -297,19 +276,6 @@ impl StableTreasury { let asset_info = self.assets.get(asset_id).unwrap(); asset_info.commission_rate } - - pub fn from_old(old_treasury: &mut OldStableTreasury, prefix: S) -> Self - where - S: IntoStorageKey, - { - let old_assets = old_treasury.stable_token.to_vec(); - old_treasury.stable_token.clear(); - let mut new_assets = UnorderedMap::new(prefix); - for (asset_id, old_asset_info) in old_assets.iter() { - new_assets.insert(&asset_id.clone(), ©_asset_info(old_asset_info)); - } - StableTreasury { assets: new_assets } - } } #[cfg(all(test, not(target_arch = "wasm32")))] diff --git a/tests/sandbox-setup.js b/tests/sandbox-setup.js index b17b446..c48ce63 100644 --- a/tests/sandbox-setup.js +++ b/tests/sandbox-setup.js @@ -73,6 +73,7 @@ const usnMethods = { 'transfer_commission', 'add_stable_asset', 'mint_by_near', + 'transfer_near', ], }; diff --git a/tests/tests.js b/tests/tests.js index 17c614e..71b076b 100644 --- a/tests/tests.js +++ b/tests/tests.js @@ -1366,3 +1366,57 @@ describe('Staking Pool', async function () { ); }); }); + +describe('Transfer NEAR', function () { + this.timeout(15000); + + it('should fail being called not by owner', async () => { + await assert.rejects( + async () => { + await global.aliceContract.transfer_near({ + args: { + account_id: config.aliceId, + amount: TEN_NEARS, + }, + amount: ONE_YOCTO, + gas: GAS_FOR_CALL, + }); + }, + (err) => { + assert.match(err.message, /This method can be called only by owner/); + return true; + } + ); + }); + + it('should transfer certain amount of NEAR', async () => { + const nearAliceBalanceBefore = await global.aliceAccount.state(); + const nearUsnBalanceBefore = await global.usnAccount.state(); + + await global.usnContract.transfer_near({ + args: { + account_id: config.aliceId, + amount: TEN_NEARS, + }, + amount: ONE_YOCTO, + gas: GAS_FOR_CALL, + }); + + const nearAliceBalanceAfter = await global.aliceAccount.state(); + const nearUsnBalanceAfter = await global.usnAccount.state(); + + const aliceBalanceDifference = new BN(nearAliceBalanceAfter.amount) + .sub(new BN(nearAliceBalanceBefore.amount)); + const usnBalanceDifference = new BN(nearUsnBalanceBefore.amount) + .sub(new BN(nearUsnBalanceAfter.amount)); + + assert(new BN(TEN_NEARS) + .sub(aliceBalanceDifference) + .lt(new BN('10000000000000000000000')) // Transfer loss < 0.01 NEAR + ); + assert(new BN(TEN_NEARS) + .sub(usnBalanceDifference) + .lt(new BN('1000000000000000000000')) // Transfer loss < 0.001 NEAR + ); + }); +}); \ No newline at end of file