Skip to content
2 changes: 1 addition & 1 deletion ref-farming/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ref_farming"
version = "1.0.1"
version = "1.1.0"
authors = ["Marco Sun <[email protected]>"]
edition = "2018"

Expand Down
11 changes: 11 additions & 0 deletions ref-farming/release_notes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Release Notes

### Version 1.1.0
1. add claim_and_withdraw interfaces;

### Version 1.0.2
1. 80T gas for seed withdraw resolve, 10T gas for reward withdraw resolve;
2. add get_user_storage_state interface;

### Version 1.0.1
1. Increase estimate gas for resolve transfer to 20T;
120 changes: 98 additions & 22 deletions ref-farming/src/actions_of_reward.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@

use std::convert::TryInto;
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, Promise, PromiseResult};

use crate::utils::{ext_fungible_token, ext_self, GAS_FOR_FT_TRANSFER, GAS_FOR_RESOLVE_TRANSFER, parse_farm_id};
use crate::errors::*;
Expand Down Expand Up @@ -44,9 +43,30 @@ impl Contract {
self.assert_storage_usage(&sender_id);
}

/// if withdraw_all_tokens is true, withdraw all tokens,
/// or just withdraw the reward token of this farm.
pub fn claim_and_withdraw_by_farm(&mut self, farm_id: FarmId, withdraw_all_tokens: bool) {
let sender_id = env::predecessor_account_id();
self.claim_reward_by_farm(farm_id.clone());
if withdraw_all_tokens {
self.internal_withdraw_all_rewards(&sender_id, None);
} else {
if let Some(farm) = self.data().farms.get(&farm_id) {
let token_id = farm.get_reward_token();
self.internal_withdraw_all_rewards(&sender_id, Some(&token_id));
}
}
}

pub fn claim_and_withdraw_by_seed(&mut self, seed_id: SeedId) {
let sender_id = env::predecessor_account_id();
self.claim_reward_by_seed(seed_id.clone());
self.internal_withdraw_all_rewards(&sender_id, None);
}

/// Withdraws given reward token of given user.
#[payable]
pub fn withdraw_reward(&mut self, token_id: ValidAccountId, amount: Option<U128>) {
pub fn withdraw_reward(&mut self, token_id: ValidAccountId, amount: Option<U128>) -> Promise {
assert_one_yocto();

let token_id: AccountId = token_id.into();
Expand All @@ -59,22 +79,27 @@ impl Contract {
// Note: subtraction, will be reverted if the promise fails.
let amount = farmer.get_ref_mut().sub_reward(&token_id, amount);
self.data_mut().farmers.insert(&sender_id, &farmer);
ext_fungible_token::ft_transfer(
sender_id.clone().try_into().unwrap(),
amount.into(),
None,
&token_id,
1,
GAS_FOR_FT_TRANSFER,
)
.then(ext_self::callback_post_withdraw_reward(
token_id,
sender_id,
amount.into(),
&env::current_account_id(),
0,
GAS_FOR_RESOLVE_TRANSFER,
));

self.internal_send_tokens(&sender_id, &token_id, amount)
}

/// Withdraws given reward tokens of given user.
#[payable]
pub fn withdraw_rewards(&mut self, token_ids: Vec<ValidAccountId>) {
assert_one_yocto();

let tokens = token_ids.iter().map(|x| x.clone().into()).collect::<Vec<String>>();

let sender_id = env::predecessor_account_id();
let mut farmer = self.get_farmer(&sender_id);
let withdraw_amounts: Vec<_> = tokens.iter().map(|token_id| farmer.get_ref_mut().sub_reward(&token_id, 0)).collect();
self.data_mut().farmers.insert(&sender_id, &farmer);

for (token_id, amount) in tokens.into_iter().zip(withdraw_amounts) {
if amount > 0 {
self.internal_send_tokens(&sender_id, &token_id, amount);
}
}
}

#[private]
Expand All @@ -83,7 +108,7 @@ impl Contract {
token_id: AccountId,
sender_id: AccountId,
amount: U128,
) {
) -> U128 {
assert_eq!(
env::promise_results_count(),
1,
Expand All @@ -100,6 +125,7 @@ impl Contract {
)
.as_bytes(),
);
amount.into()
}
PromiseResult::Failed => {
env::log(
Expand All @@ -113,8 +139,9 @@ impl Contract {
let mut farmer = self.get_farmer(&sender_id);
farmer.get_ref_mut().add_reward(&token_id, amount.0);
self.data_mut().farmers.insert(&sender_id, &farmer);
0.into()
}
};
}
}
}

Expand Down Expand Up @@ -153,6 +180,55 @@ fn claim_user_reward_from_farm(
}

impl Contract {

/// if token was given, then just withdraw that token, or withdraw all tokens
pub(crate) fn internal_withdraw_all_rewards(&mut self, farmer_id: &AccountId, token: Option<&AccountId>) {

let view_farmer = self.get_farmer(&farmer_id);
let tokens = {
if let Some(token) = token {
vec![token.clone()]
} else {
view_farmer.get_ref().rewards.keys().map(|x| x.clone()).collect::<Vec<_>>()
}
};

let mut farmer = view_farmer;
let withdraw_amounts: Vec<_> = tokens.iter().map(|token_id| farmer.get_ref_mut().sub_reward(&token_id, 0)).collect();
self.data_mut().farmers.insert(farmer_id, &farmer);

for (token_id, amount) in tokens.into_iter().zip(withdraw_amounts) {
if amount > 0 {
self.internal_send_tokens(farmer_id, &token_id, amount);
}
}
}

/// Sends given amount to given user and if it fails, returns it back to user's balance.
/// Tokens must already be subtracted from internal balance.
pub(crate) fn internal_send_tokens(
&self,
sender_id: &AccountId,
token_id: &AccountId,
amount: Balance,
) -> Promise {
ext_fungible_token::ft_transfer(
sender_id.clone(),
U128(amount),
None,
token_id,
1,
GAS_FOR_FT_TRANSFER,
)
.then(ext_self::callback_post_withdraw_reward(
token_id.clone(),
sender_id.clone(),
U128(amount),
&env::current_account_id(),
0,
GAS_FOR_RESOLVE_TRANSFER,
))
}

pub(crate) fn internal_claim_user_reward_by_seed_id(
&mut self,
Expand Down
18 changes: 11 additions & 7 deletions ref-farming/src/actions_of_seed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use near_sdk::{AccountId, Balance, PromiseResult};

use crate::utils::{
assert_one_yocto, ext_multi_fungible_token, ext_fungible_token,
ext_self, wrap_mft_token_id, parse_seed_id, GAS_FOR_FT_TRANSFER, GAS_FOR_RESOLVE_TRANSFER
ext_self, wrap_mft_token_id, parse_seed_id, GAS_FOR_FT_TRANSFER, GAS_FOR_RESOLVE_WITHDRAW_SEED
};
use crate::errors::*;
use crate::farm_seed::SeedType;
Expand Down Expand Up @@ -41,7 +41,7 @@ impl Contract {
amount.into(),
&env::current_account_id(),
0,
GAS_FOR_RESOLVE_TRANSFER,
GAS_FOR_RESOLVE_WITHDRAW_SEED,
));
}
SeedType::MFT => {
Expand All @@ -61,7 +61,7 @@ impl Contract {
amount.into(),
&env::current_account_id(),
0,
GAS_FOR_RESOLVE_TRANSFER,
GAS_FOR_RESOLVE_WITHDRAW_SEED,
));
}
}
Expand All @@ -74,7 +74,7 @@ impl Contract {
seed_id: SeedId,
sender_id: AccountId,
amount: U128,
) {
) -> U128 {
assert_eq!(
env::promise_results_count(),
1,
Expand Down Expand Up @@ -102,6 +102,7 @@ impl Contract {
farmer.get_ref_mut().add_seed(&seed_id, amount);
self.data_mut().seeds.insert(&seed_id, &farm_seed);
self.data_mut().farmers.insert(&sender_id, &farmer);
0.into()
},
PromiseResult::Successful(_) => {
env::log(
Expand All @@ -111,8 +112,9 @@ impl Contract {
)
.as_bytes(),
);
amount.into()
}
};
}
}

#[private]
Expand All @@ -121,7 +123,7 @@ impl Contract {
seed_id: SeedId,
sender_id: AccountId,
amount: U128,
) {
) -> U128 {
assert_eq!(
env::promise_results_count(),
1,
Expand Down Expand Up @@ -149,6 +151,7 @@ impl Contract {
farmer.get_ref_mut().add_seed(&seed_id, amount);
self.data_mut().seeds.insert(&seed_id, &farm_seed);
self.data_mut().farmers.insert(&sender_id, &farmer);
0.into()
},
PromiseResult::Successful(_) => {
env::log(
Expand All @@ -158,8 +161,9 @@ impl Contract {
)
.as_bytes(),
);
amount.into()
}
};
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions ref-farming/src/farmer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ impl Farmer {
pub(crate) fn sub_reward(&mut self, token: &AccountId, amount: Balance) -> Balance {
let value = *self.rewards.get(token).expect(ERR21_TOKEN_NOT_REG);
assert!(value >= amount, "{}", ERR22_NOT_ENOUGH_TOKENS);
if amount == 0 {
self.rewards.remove(&token.clone());
if amount == 0 || amount == value {
self.rewards.remove(token);
value
} else {
self.rewards.insert(token.clone(), value - amount);
Expand Down
6 changes: 4 additions & 2 deletions ref-farming/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ pub const MIN_SEED_DEPOSIT: u128 = 1_000_000_000_000_000_000;
pub const MAX_ACCOUNT_LENGTH: u128 = 64;
/// Amount of gas for fungible token transfers.
pub const GAS_FOR_FT_TRANSFER: Gas = 10_000_000_000_000;
/// hotfix_insuffient_gas_for_mft_resolve_transfer, increase from 5T to 20T
pub const GAS_FOR_RESOLVE_TRANSFER: Gas = 20_000_000_000_000;
/// Amount of gas for reward token transfers resolve.
pub const GAS_FOR_RESOLVE_TRANSFER: Gas = 10_000_000_000_000;
/// Amount of gas for seed token transfers resolve.
pub const GAS_FOR_RESOLVE_WITHDRAW_SEED: Gas = 80_000_000_000_000;
pub const MFT_TAG: &str = "@";


Expand Down
21 changes: 21 additions & 0 deletions ref-farming/src/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ pub struct Metadata {
pub reward_count: U64,
}

#[derive(Serialize, Deserialize, PartialEq)]
#[serde(crate = "near_sdk::serde")]
#[cfg_attr(not(target_arch = "wasm32"), derive(Debug))]
pub struct StorageState {
pub deposit: U128,
pub usage: U128,
}

#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
#[serde(crate = "near_sdk::serde")]
pub struct FarmInfo {
Expand Down Expand Up @@ -287,4 +295,17 @@ impl Contract {
String::from("0")
}
}

/// Get farmer's storage deposit and needed in the account of current version
pub fn get_user_storage_state(&self, account_id: ValidAccountId) -> Option<StorageState> {
let (locked, deposited) = self.internal_farmer_storage(account_id.as_ref());
if locked > 0 {
Some(StorageState {
deposit: U128(deposited),
usage: U128(locked),
})
} else {
None
}
}
}
7 changes: 7 additions & 0 deletions ref-farming/tests/common/views.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use near_sdk_sim::{view, ContractAccount};

use super::utils::to_va;
use ref_farming::{ContractContract as Farming, FarmInfo};
use test_token::ContractContract as TestToken;
use std::collections::HashMap;

#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
Expand Down Expand Up @@ -184,6 +185,12 @@ pub(crate) fn show_storage_balance(farming: &ContractAccount<Farming>, farmer: S
ret
}

pub(crate) fn balance_of(token: &ContractAccount<TestToken>, account_id: String) -> u128 {
view!(token.ft_balance_of(to_va(account_id.clone())))
.unwrap_json::<U128>()
.0
}

// ============= Assertions ===============
#[allow(dead_code)]
pub(crate) fn assert_farming(
Expand Down
Loading