Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
0e623cd
reorg MIN_RESERVE of stable, rated, degen pool to inner precision / 1000
Dec 7, 2024
d338e52
reorg MIN_RESERVE of stable, rated, degen pool to inner precision / 1000
Dec 7, 2024
519a07f
build release
MagicGordon Dec 7, 2024
0bee0a4
Merge branch 'main' into accumulated-updates
MagicGordon Jan 14, 2025
8322bc0
amendments according to audition recommendations.
MagicGordon Jan 15, 2025
26be36a
add skip_degen_price_sync param.
MagicGordon Feb 13, 2025
5d8d059
fix tests
MagicGordon Feb 13, 2025
072abcf
Merge branch 'main' into accumulated-updates
MagicGordon Mar 19, 2025
f0ed401
add SwapVolumeU256
MagicGordon Mar 19, 2025
38447c2
update reference
MagicGordon Mar 19, 2025
5ec8821
fix test
MagicGordon Mar 19, 2025
e854472
add test
MagicGordon Mar 20, 2025
9fa3edc
update pool volumes
MagicGordon Mar 20, 2025
e23d07f
Merge branch 'main' into accumulated-updates
MagicGordon Apr 9, 2025
dcd8c27
add get_pool_shares_batch
MagicGordon Jun 17, 2025
8d63b4e
Merge branch 'main' into accumulated-updates
MagicGordon Jul 2, 2025
6b5b518
add batch_views
MagicGordon Jul 2, 2025
1749f36
Merge branch 'main' into accumulated-updates
marco-sundsk Sep 16, 2025
d05c093
support secure sender whitelist in client echo feature
marco-sundsk Sep 17, 2025
f42f4da
force legal pattern when using wildcard and add comprehensive tests
marco-sundsk Sep 17, 2025
5dfd2a0
clean test comments
marco-sundsk Sep 17, 2025
a352f12
gas improvement
marco-sundsk Oct 2, 2025
f0aff36
gas improvement
marco-sundsk Oct 2, 2025
049ac79
fix release_notes
marco-sundsk Oct 2, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions mock-boost-farming/src/token_receiver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ impl FungibleTokenReceiver for Contract {
msg: String,
) -> PromiseOrValue<U128> {
assert!(self.data().state == RunningState::Running, "{}", E004_CONTRACT_PAUSED);
log!("prepaid gas: {}", env::prepaid_gas());

let amount: u128 = amount.into();
let token_id = env::predecessor_account_id();
Expand Down
2 changes: 1 addition & 1 deletion ref-exchange/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ref-exchange"
version = "1.9.14"
version = "1.9.15"
authors = ["Illia Polosukhin <illia.polosukhin@gmail.com>"]
edition = "2018"
publish = false
Expand Down
28 changes: 28 additions & 0 deletions ref-exchange/release_notes.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,33 @@
# Release Notes

### Version 1.9.15
```
6VT8PzHwyphkL64Gi7GLS8YyBqmeVU8y8xjSd5ej53sF
```
1. reduce gas for callback of client_echo ft_transfer_call from 20T to 5T.
2. add a new optional arg 'extra_tgas_for_client_echo' for client_echo action.
```rust
Execute {
referral_id: Option<ValidAccountId>,
/// List of sequential actions.
actions: Vec<Action>,
/// If not None, use ft_transfer_call
/// to send token_out back to predecessor with this msg.
client_echo: Option<String>,
skip_unwrap_near: Option<bool>,
swap_out_recipient: Option<ValidAccountId>,
skip_degen_price_sync: Option<bool>,
/// extra Tgas for ft_on_transfer
extra_tgas_for_client_echo: Option<u32>,
},
```
The default value of this arg is 15, means an extra 15T gas will be passed to the token contract beyond the 30T gas requried by NEP-141 'ft_transfer_call'. The client echo sender can set a small number to save gas, for example:
```bash
# manually set extra gas to 7T, so the token_out.near contract would be guaranteed to have at least 37Tgas as prepaid gas in its 'ft_transfer_call'.
{ "msg": "{\"force\":0,\"actions\":[{\"pool_id\":0,\"token_in\":\"token_in.near\",\"token_out\":\"token_out.near\",\"min_amount_out\":\"1\"}],\"client_echo\":\"{\"receiver_id\":\"echo_receiver.near\"}\",\"extra_tgas_for_client_echo\":7}", "amount": "1000", "sender_id": "echo_sender.near" }
```


### Version 1.9.14
```
G1mrfT8dceTrrjn95LeCq6HS2LbFktd9XWp49oXZAdXH
Expand Down
13 changes: 7 additions & 6 deletions ref-exchange/src/account_deposit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use near_sdk::{
AccountId, Balance, PromiseResult, StorageUsage,
};
use crate::legacy::{AccountV1, AccountV2};
use crate::utils::{ext_self, ext_wrap_near, GAS_FOR_FT_TRANSFER, GAS_FOR_FT_TRANSFER_CALL, GAS_FOR_RESOLVE_TRANSFER, GAS_FOR_NEAR_WITHDRAW};
use crate::utils::{ext_self, ext_wrap_near, GAS_FOR_FT_TRANSFER, GAS_FOR_FT_TRANSFER_CALL, GAS_FOR_NEAR_WITHDRAW, GAS_FOR_CB_FT_TRANSFER};
use crate::*;

// [AUDIT_01]
Expand Down Expand Up @@ -609,7 +609,7 @@ impl Contract {
U128(amount),
&env::current_account_id(),
0,
GAS_FOR_RESOLVE_TRANSFER,
GAS_FOR_CB_FT_TRANSFER,
))
} else {
ext_fungible_token::ft_transfer(
Expand All @@ -626,7 +626,7 @@ impl Contract {
U128(amount),
&env::current_account_id(),
0,
GAS_FOR_RESOLVE_TRANSFER,
GAS_FOR_CB_FT_TRANSFER,
))
}
}
Expand All @@ -636,7 +636,8 @@ impl Contract {
sender_id: &AccountId,
token_id: &AccountId,
amount: Balance,
msg: String
msg: String,
extra_gas: Gas,
) -> Promise {
ext_fungible_token::ft_transfer_call(
sender_id.clone(),
Expand All @@ -645,15 +646,15 @@ impl Contract {
msg,
token_id,
1,
GAS_FOR_FT_TRANSFER_CALL,
GAS_FOR_FT_TRANSFER_CALL + extra_gas,
)
.then(ext_self::exchange_callback_post_withdraw(
token_id.clone(),
sender_id.clone(),
U128(amount),
&env::current_account_id(),
0,
GAS_FOR_RESOLVE_TRANSFER,
GAS_FOR_CB_FT_TRANSFER,
))
}
}
10 changes: 5 additions & 5 deletions ref-exchange/src/multi_fungible_token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use near_contract_standards::fungible_token::metadata::FungibleTokenMetadata;
use near_sdk::json_types::{ValidAccountId, U128};
use near_sdk::{ext_contract, near_bindgen, Balance, PromiseOrValue};

use crate::utils::{GAS_FOR_FT_TRANSFER_CALL, GAS_FOR_RESOLVE_TRANSFER, NO_DEPOSIT};
use crate::utils::{GAS_FOR_MFT_TRANSFER_CALL, GAS_FOR_MFT_RESOLVE_TRANSFER, NO_DEPOSIT};
use crate::*;

#[ext_contract(ext_self)]
Expand Down Expand Up @@ -253,7 +253,7 @@ impl Contract {
msg,
receiver_id.as_ref(),
NO_DEPOSIT,
env::prepaid_gas() - GAS_FOR_FT_TRANSFER_CALL,
env::prepaid_gas() - GAS_FOR_MFT_TRANSFER_CALL - GAS_FOR_MFT_RESOLVE_TRANSFER,
)
.then(ext_self::mft_resolve_transfer(
token_id,
Expand All @@ -262,7 +262,7 @@ impl Contract {
amount,
&env::current_account_id(),
NO_DEPOSIT,
GAS_FOR_RESOLVE_TRANSFER,
GAS_FOR_MFT_RESOLVE_TRANSFER,
))
.into()
}
Expand Down Expand Up @@ -292,7 +292,7 @@ impl Contract {
msg,
receiver_id.as_ref(),
NO_DEPOSIT,
env::prepaid_gas() - GAS_FOR_FT_TRANSFER_CALL,
env::prepaid_gas() - GAS_FOR_MFT_TRANSFER_CALL - GAS_FOR_MFT_RESOLVE_TRANSFER,
)
.then(ext_self::mft_resolve_transfer(
token_id,
Expand All @@ -301,7 +301,7 @@ impl Contract {
U128(transfer_amount),
&env::current_account_id(),
NO_DEPOSIT,
GAS_FOR_RESOLVE_TRANSFER,
GAS_FOR_MFT_RESOLVE_TRANSFER,
))
.into()
}
Expand Down
7 changes: 6 additions & 1 deletion ref-exchange/src/token_receiver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use near_sdk::serde::{Deserialize, Serialize};
use near_sdk::{serde_json, PromiseOrValue};

use crate::*;
use crate::utils::DEFAULT_EXTRA_TGAS;

pub const VIRTUAL_ACC: &str = "@";

Expand Down Expand Up @@ -32,6 +33,8 @@ enum TokenReceiverMessage {
skip_unwrap_near: Option<bool>,
swap_out_recipient: Option<ValidAccountId>,
skip_degen_price_sync: Option<bool>,
/// extra Tgas for ft_on_transfer
extra_tgas_for_client_echo: Option<u32>,
},
HotZap {
referral_id: Option<ValidAccountId>,
Expand Down Expand Up @@ -115,7 +118,9 @@ impl FungibleTokenReceiver for Contract {
skip_unwrap_near,
swap_out_recipient,
skip_degen_price_sync,
extra_tgas_for_client_echo,
} => {
let extra_tgas: Gas = extra_tgas_for_client_echo.unwrap_or(DEFAULT_EXTRA_TGAS) as Gas * 1_000_000_000_000 as Gas;
assert!(!(swap_out_recipient.is_some() && client_echo.is_some()), "client_echo and swap_out_recipient cannot have value at the same time");
assert_ne!(actions.len(), 0, "{}", ERR72_AT_LEAST_ONE_SWAP);
if client_echo.is_some() {
Expand All @@ -134,7 +139,7 @@ impl FungibleTokenReceiver for Contract {
}
for (token_out, amount_out) in out_amounts.into_iter() {
if let Some(ref message) = client_echo {
self.internal_send_token_with_msg(sender_id.as_ref(), &token_out, amount_out, message.clone());
self.internal_send_token_with_msg(sender_id.as_ref(), &token_out, amount_out, message.clone(), extra_tgas);
} else {
self.internal_send_tokens(swap_out_recipient.as_ref().unwrap_or(&sender_id).as_ref(), &token_out, amount_out, skip_unwrap_near);
}
Expand Down
8 changes: 6 additions & 2 deletions ref-exchange/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,18 @@ pub const NO_DEPOSIT: u128 = 0;
pub const GAS_FOR_BASIC_OP: Gas = 10_000_000_000_000;

/// hotfix_insuffient_gas_for_mft_resolve_transfer.
pub const GAS_FOR_RESOLVE_TRANSFER: Gas = 20_000_000_000_000;
pub const GAS_FOR_MFT_TRANSFER_CALL: Gas = 25_000_000_000_000;
pub const GAS_FOR_MFT_RESOLVE_TRANSFER: Gas = 20_000_000_000_000;

pub const GAS_FOR_FT_TRANSFER_CALL: Gas = 25_000_000_000_000 + GAS_FOR_RESOLVE_TRANSFER;
pub const GAS_FOR_FT_TRANSFER_CALL: Gas = 30_000_000_000_000;
pub const DEFAULT_EXTRA_TGAS: u32 = 15;

/// Amount of gas for fungible token transfers, increased to 20T to support AS token contracts.
pub const GAS_FOR_FT_TRANSFER: Gas = 20_000_000_000_000;
pub const GAS_FOR_NEAR_WITHDRAW: Gas = 20_000_000_000_000;

pub const GAS_FOR_CB_FT_TRANSFER: Gas = 5_000_000_000_000;

/// Fee divisor, allowing to provide fee in bps.
pub const FEE_DIVISOR: u32 = 10_000;
pub const MAX_ADMIN_FEE_BPS: u32 = 8_000;
Expand Down
175 changes: 175 additions & 0 deletions ref-exchange/tests/test_extra_gas_for_client_echo.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
use crate::common::utils::*;
pub mod common;

use test_token::ContractContract as TestToken;
use mock_boost_farming::{ContractContract as MockBoostFarming};

use near_sdk::{json_types::U128, serde_json::Value, AccountId};
use near_sdk_sim::{call, deploy, view, to_yocto, ContractAccount, ExecutionResult, UserAccount};

near_sdk_sim::lazy_static_include::lazy_static_include_bytes! {
MOCK_BOOST_FARMING_WASM_BYTES => "../res/mock_boost_farming.wasm",
}

fn do_swap(
user: &UserAccount,
contract: &ContractAccount<TestToken>,
actions: Vec<String>,
amount: u128,
client_echo: Option<String>,
swap_out_recipient: Option<AccountId>,
extra_tgas: Option<u32>,
) -> ExecutionResult {
let client_echo = if let Some(client_echo) = client_echo {
format!(",\"client_echo\":\"{}\"", client_echo)
} else {
"".to_string()
};
let swap_out_recipient = if let Some(swap_out_recipient) = swap_out_recipient {
format!(",\"swap_out_recipient\":\"{}\"", swap_out_recipient)
} else {
"".to_string()
};
let extra_tgas = if let Some(extra_tgas) = extra_tgas {
format!(",\"extra_tgas_for_client_echo\":{}", extra_tgas)
} else {
"".to_string()
};
let actions_str = actions.join(", ");
let msg_str = format!(
"{{\"actions\": [{}]{}{}{}}}",
actions_str, client_echo, swap_out_recipient, extra_tgas
);
call!(
user,
contract.ft_transfer_call(to_va(swap()), amount.into(), None, msg_str),
deposit = 1
)
}

fn pack_action(
pool_id: u32,
token_in: &str,
token_out: &str,
min_amount_out: u128,
) -> String {

format!(
"{{\"pool_id\": {}, \"token_in\": \"{}\", \"token_out\": \"{}\", \"min_amount_out\": \"{}\"}}",
pool_id, token_in, token_out, min_amount_out
)

}

fn boost_farming() -> AccountId {
"boost_farming".to_string()
}

#[test]
fn test_extra_gas() {
let (root, owner, pool, token1, token2, _) = setup_pool_with_liquidity();
let new_user = root.create_user("new_user".to_string(), to_yocto("100"));
let mock_boost_farming = deploy!(
contract: MockBoostFarming,
contract_id: boost_farming(),
bytes: &MOCK_BOOST_FARMING_WASM_BYTES,
signer_account: root,
init_method: new(root.account_id())
);
let outcome = call!(
root,
mock_boost_farming.create_seed(token2.account_id(),24, Some(U128(0)), Some(0)),
deposit = 1
);
outcome.assert_success();
call!(
pool.user_account,
mock_boost_farming.storage_deposit(None, None),
deposit = to_yocto("1")
)
.assert_success();

call!(
mock_boost_farming.user_account,
token1.mint(to_va(mock_boost_farming.user_account.account_id.clone()), U128(to_yocto("10")))
)
.assert_success();
call!(
mock_boost_farming.user_account,
token2.storage_deposit(None, None),
deposit = to_yocto("1")
)
.assert_success();
call!(
new_user,
token2.storage_deposit(None, None),
deposit = to_yocto("1")
)
.assert_success();
assert_eq!(balance_of(&token1, &mock_boost_farming.user_account.account_id), to_yocto("10"));

let action = pack_action(0, &token1.account_id(), &token2.account_id(), 0);

call!(
owner,
pool.extend_client_echo_token_id_whitelist(vec![token1.account_id()]),
deposit = 1
)
.assert_success();

assert_eq!(balance_of(&token1, &mock_boost_farming.user_account.account_id), to_yocto("10"));
assert_eq!(balance_of(&token2, &mock_boost_farming.user_account.account_id), to_yocto("0"));

call!(
owner,
pool.extend_client_echo_sender_id_whitelist(vec![mock_boost_farming.account_id()]),
deposit = 1
)
.assert_success();

// use default 15T as extra gas by not passing extra_tgas_for_client_echo field
let out_come = do_swap(
&mock_boost_farming.user_account,
&token1,
vec![action.clone()],
to_yocto("1"),
Some("\\\"Free\\\"".to_string()),
None,
None,
);
out_come.assert_success();
// println!("final outcome: {:#?}", out_come);
// println!("promise_results: {:#?}", out_come.promise_results());
// println!("promise_errors: {:#?}", out_come.promise_errors());
// println!("logs: {:#?}", get_logs(&out_come));
assert_eq!(*get_logs(&out_come).get(4).unwrap(), "prepaid gas: 15000000000000".to_string());

// mannually set extra gas to 10T
let out_come = do_swap(
&mock_boost_farming.user_account,
&token1,
vec![action.clone()],
to_yocto("1"),
Some("\\\"Free\\\"".to_string()),
None,
Some(10_u32),
);
out_come.assert_success();
assert_eq!(*get_logs(&out_come).get(4).unwrap(), "prepaid gas: 10000000000000".to_string());

// extra gas is less than needed, cause an error.
let out_come = do_swap(
&mock_boost_farming.user_account,
&token1,
vec![action.clone()],
to_yocto("1"),
Some("\\\"Free\\\"".to_string()),
None,
Some(5_u32),
);
out_come.assert_success();
println!("logs: {:#?}", get_logs(&out_come));
assert_eq!(get_error_count(&out_come), 1);
assert_eq!(*get_logs(&out_come).get(4).unwrap(), "prepaid gas: 5000000000000".to_string());

}
Loading