Skip to content
This repository was archived by the owner on Jun 1, 2026. It is now read-only.

Commit 7183809

Browse files
committed
Make EVM approval max value explicit
1 parent d92723d commit 7183809

4 files changed

Lines changed: 58 additions & 14 deletions

File tree

crates/gem_evm/src/encode.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ pub fn encode_erc20_transfer(to: &str, amount: &BigInt) -> Result<Vec<u8>, Box<d
1414
.abi_encode())
1515
}
1616

17-
pub fn encode_erc20_approve(spender: &str) -> Result<Vec<u8>, Box<dyn Error + Send + Sync>> {
17+
pub fn encode_erc20_approve_max_value(spender: &str) -> Result<Vec<u8>, Box<dyn Error + Send + Sync>> {
1818
Ok(IERC20::approveCall {
1919
spender: Address::from_str(spender)?,
2020
value: U256::MAX,
@@ -41,3 +41,18 @@ pub fn encode_erc1155_transfer(from: &str, to: &str, token_id: &str) -> Result<V
4141
}
4242
.abi_encode())
4343
}
44+
45+
#[cfg(test)]
46+
mod tests {
47+
use super::*;
48+
49+
#[test]
50+
fn test_encode_erc20_approve_max_value() {
51+
let spender = "0x2b5AD5c4795c026514f8317c7a215E218dccD6cF";
52+
let data = encode_erc20_approve_max_value(spender).unwrap();
53+
let call = IERC20::approveCall::abi_decode(&data).unwrap();
54+
55+
assert_eq!(call.spender, Address::from_str(spender).unwrap());
56+
assert_eq!(call.value, U256::MAX);
57+
}
58+
}

crates/gem_evm/src/provider/preload_mapper.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use primitives::{
1212
fee::GasPriceType,
1313
};
1414

15-
use crate::encode::{encode_erc20_approve, encode_erc20_transfer, encode_erc721_transfer, encode_erc1155_transfer};
15+
use crate::encode::{encode_erc20_approve_max_value, encode_erc20_transfer, encode_erc721_transfer, encode_erc1155_transfer};
1616
use crate::everstake::{DEFAULT_ALLOWED_INTERCHANGE_NUM, EVERSTAKE_ACCOUNTING_ADDRESS, EVERSTAKE_POOL_ADDRESS, EVERSTAKE_SOURCE, IAccounting, IPool};
1717
use crate::fee_calculator::FeeCalculator;
1818
use crate::models::fee::EthereumFeeHistory;
@@ -92,7 +92,11 @@ pub fn get_transaction_params(chain: EVMChain, input: &TransactionLoadInput) ->
9292
}
9393
TransactionInputType::Swap(from_asset, _, swap_data) => {
9494
if let Some(approval) = &swap_data.data.approval {
95-
Ok(TransactionParams::new(approval.token.clone(), encode_erc20_approve(&approval.spender)?, BigInt::from(0)))
95+
Ok(TransactionParams::new(
96+
approval.token.clone(),
97+
encode_erc20_approve_max_value(&approval.spender)?,
98+
BigInt::from(0),
99+
))
96100
} else {
97101
match from_asset.id.token_subtype() {
98102
AssetSubtype::NATIVE => Ok(TransactionParams::new(
@@ -111,7 +115,11 @@ pub fn get_transaction_params(chain: EVMChain, input: &TransactionLoadInput) ->
111115
}
112116
}
113117
}
114-
TransactionInputType::TokenApprove(_, approval) => Ok(TransactionParams::new(approval.token.clone(), encode_erc20_approve(&approval.spender)?, BigInt::from(0))),
118+
TransactionInputType::TokenApprove(_, approval) => Ok(TransactionParams::new(
119+
approval.token.clone(),
120+
encode_erc20_approve_max_value(&approval.spender)?,
121+
BigInt::from(0),
122+
)),
115123
TransactionInputType::Generic(_, _, extra) => Ok(TransactionParams::new(
116124
extra.to.clone(),
117125
extra.data.clone().unwrap_or_default(),
@@ -150,7 +158,7 @@ pub fn get_transaction_params(chain: EVMChain, input: &TransactionLoadInput) ->
150158
},
151159
TransactionInputType::Earn(_, _, earn_data) => {
152160
if let Some(approval) = &earn_data.approval {
153-
Ok(TransactionParams::new_approval(approval.token.clone(), encode_erc20_approve(&approval.spender)?))
161+
Ok(TransactionParams::new_approval(approval.token.clone(), encode_erc20_approve_max_value(&approval.spender)?))
154162
} else {
155163
Ok(TransactionParams::new(
156164
earn_data.contract_address.clone(),

crates/gem_evm/src/signer/chain_signer.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use primitives::{ChainSigner, EVMChain, NFTType, SignerError, SignerInput, Stake
88

99
use super::model::TransactionParams;
1010
use super::sign_eip1559_tx;
11-
use crate::encode::{encode_erc20_approve, encode_erc20_transfer, encode_erc721_transfer, encode_erc1155_transfer};
11+
use crate::encode::{encode_erc20_approve_max_value, encode_erc20_transfer, encode_erc721_transfer, encode_erc1155_transfer};
1212

1313
#[allow(dead_code)]
1414
pub struct EvmChainSigner {
@@ -53,7 +53,7 @@ impl ChainSigner for EvmChainSigner {
5353
let params = TransactionParams::from_input(input)?;
5454
let approval = input.input_type.get_approval_data()?;
5555
sign_and_encode(
56-
&build_eip1559_transaction(&params, &approval.token, U256::ZERO, Bytes::from(encode_erc20_approve(&approval.spender)?))?,
56+
&build_eip1559_transaction(&params, &approval.token, U256::ZERO, Bytes::from(encode_erc20_approve_max_value(&approval.spender)?))?,
5757
private_key,
5858
)
5959
}
@@ -187,7 +187,7 @@ fn sign_contract_call(
187187
let params = TransactionParams::from_input(input)?;
188188

189189
if let Some(approval) = approval {
190-
let approval_transaction = build_eip1559_transaction(&params, &approval.token, U256::ZERO, Bytes::from(encode_erc20_approve(&approval.spender)?))?;
190+
let approval_transaction = build_eip1559_transaction(&params, &approval.token, U256::ZERO, Bytes::from(encode_erc20_approve_max_value(&approval.spender)?))?;
191191
let main_params = TransactionParams {
192192
nonce: params.nonce + 1,
193193
gas_limit,

crates/yielder/src/yo/client.rs

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -86,12 +86,7 @@ impl YoGatewayClient {
8686
let allowance = self.ethereum_client.call_contract(token, IERC20::allowanceCall { owner, spender }).await?;
8787

8888
if allowance < amount {
89-
Ok(Some(ApprovalData {
90-
token: token.to_string(),
91-
spender: spender.to_string(),
92-
value: amount.to_string(),
93-
is_unlimited: false,
94-
}))
89+
Ok(Some(build_token_approval_data(token, spender, amount)))
9590
} else {
9691
Ok(None)
9792
}
@@ -111,6 +106,15 @@ fn convert_to_assets_ceil(shares: U256, total_assets: U256, total_supply: U256)
111106
(shares * total_assets + total_supply - U256::from(1)) / total_supply
112107
}
113108

109+
fn build_token_approval_data(token: Address, spender: Address, amount: U256) -> ApprovalData {
110+
ApprovalData {
111+
token: token.to_string(),
112+
spender: spender.to_string(),
113+
value: amount.to_string(),
114+
is_unlimited: true,
115+
}
116+
}
117+
114118
#[cfg(test)]
115119
mod tests {
116120
use super::*;
@@ -126,4 +130,21 @@ mod tests {
126130
assert_eq!(convert_to_assets_ceil(U256::from(100), U256::from(1000), U256::ZERO), U256::ZERO);
127131
assert_eq!(convert_to_assets_ceil(U256::ZERO, U256::ZERO, U256::ZERO), U256::ZERO);
128132
}
133+
134+
#[test]
135+
fn test_build_token_approval_data() {
136+
let token = Address::from([1; 20]);
137+
let spender = Address::from([2; 20]);
138+
let amount = U256::from(1234);
139+
140+
assert_eq!(
141+
build_token_approval_data(token, spender, amount),
142+
ApprovalData {
143+
token: token.to_string(),
144+
spender: spender.to_string(),
145+
value: "1234".to_string(),
146+
is_unlimited: true,
147+
}
148+
);
149+
}
129150
}

0 commit comments

Comments
 (0)