From 3a69bbf6035df123a076f1f91011300e1c672527 Mon Sep 17 00:00:00 2001 From: Diana Carvalho Date: Wed, 29 Jan 2025 17:29:36 +0000 Subject: [PATCH] feat: Remove generalisation on user approvals manager This is a too early over generalisation. We need to encode the permit and the signature all together with the other method input variables. This way the return type will be specific to permit2 (instead Vec) anyway. For simplicity, decided to remove the generalisation and keep things simple --- don't change below this line --- ENG-4081 Took 2 hours 23 minutes Took 9 seconds Took 1 minute --- src/encoding/evm/approvals/permit2.rs | 117 ++++++++++--------------- src/encoding/mod.rs | 1 - src/encoding/router_encoder.rs | 3 +- src/encoding/user_approvals_manager.rs | 17 ---- 4 files changed, 46 insertions(+), 92 deletions(-) delete mode 100644 src/encoding/user_approvals_manager.rs diff --git a/src/encoding/evm/approvals/permit2.rs b/src/encoding/evm/approvals/permit2.rs index 392e0d2..ac673ca 100644 --- a/src/encoding/evm/approvals/permit2.rs +++ b/src/encoding/evm/approvals/permit2.rs @@ -7,9 +7,10 @@ use alloy::{ signers::{local::PrivateKeySigner, SignerSync}, transports::BoxTransport, }; -use alloy_primitives::{ChainId, U256}; +use alloy_primitives::{ChainId, Signature, U256}; use alloy_sol_types::{eip712_domain, sol, SolStruct, SolValue}; use chrono::Utc; +use num_bigint::BigUint; use tokio::runtime::Runtime; use tycho_core::Bytes; @@ -19,7 +20,6 @@ use crate::encoding::{ approvals::protocol_approvals_manager::get_client, utils::{biguint_to_u256, bytes_to_address, encode_input}, }, - user_approvals_manager::{Approval, UserApprovalsManager}, }; /// Struct for managing Permit2 operations, including encoding approvals and fetching allowance @@ -107,59 +107,48 @@ impl Permit2 { ))), } } -} -impl UserApprovalsManager for Permit2 { - /// Encodes multiple approvals into ABI-encoded data and signs them. - fn encode_approvals(&self, approvals: Vec) -> Result>, EncodingError> { + /// Creates permit single and signature + pub fn get_permit( + &self, + spender: &Bytes, + owner: &Bytes, + token: &Bytes, + amount: &BigUint, + ) -> Result<(PermitSingle, Signature), EncodingError> { let current_time = Utc::now() .naive_utc() .and_utc() .timestamp() as u64; - let mut encoded_approvals = Vec::new(); + let (_, _, nonce) = self.get_existing_allowance(owner, spender, token)?; + let expiration = U48::from(current_time + PERMIT_EXPIRATION); + let sig_deadline = U256::from(current_time + PERMIT_SIG_EXPIRATION); + let amount = U160::from(biguint_to_u256(amount)); - for approval in approvals { - let (_, _, nonce) = - self.get_existing_allowance(&approval.owner, &approval.spender, &approval.token)?; - let expiration = U48::from(current_time + PERMIT_EXPIRATION); - let sig_deadline = U256::from(current_time + PERMIT_SIG_EXPIRATION); - let amount = U160::from(biguint_to_u256(&approval.amount)); + let details = PermitDetails { token: bytes_to_address(token)?, amount, expiration, nonce }; - let details = PermitDetails { - token: bytes_to_address(&approval.token)?, - amount, - expiration, - nonce, - }; + let permit_single = PermitSingle { + details, + spender: bytes_to_address(spender)?, + sigDeadline: sig_deadline, + }; - let permit_single = PermitSingle { - details, - spender: bytes_to_address(&approval.spender)?, - sigDeadline: sig_deadline, - }; - - let domain = eip712_domain! { - name: "Permit2", - chain_id: self.chain_id, - verifying_contract: self.address, - }; - let hash = permit_single.eip712_signing_hash(&domain); - let signature = self - .signer - .sign_hash_sync(&hash) - .map_err(|e| { - EncodingError::FatalError(format!( - "Failed to sign permit2 approval with error: {}", - e - )) - })?; - let encoded = - (bytes_to_address(&approval.owner)?, permit_single, signature.as_bytes().to_vec()) - .abi_encode(); - encoded_approvals.push(encoded); - } - - Ok(encoded_approvals) + let domain = eip712_domain! { + name: "Permit2", + chain_id: self.chain_id, + verifying_contract: self.address, + }; + let hash = permit_single.eip712_signing_hash(&domain); + let signature = self + .signer + .sign_hash_sync(&hash) + .map_err(|e| { + EncodingError::FatalError(format!( + "Failed to sign permit2 approval with error: {}", + e + )) + })?; + Ok((permit_single, signature)) } } @@ -222,7 +211,7 @@ mod tests { } #[test] - fn test_encode_approvals() { + fn test_get_permit() { // Set up a mock private key for signing let private_key = B256::from_str("4c0883a69102937d6231471b5dbb6204fe512961708279feb1be6ae5538da033") @@ -234,21 +223,10 @@ mod tests { let spender = Bytes::from_str("0xba12222222228d8ba445958a75a0704d566bf2c8").unwrap(); let token = Bytes::from_str("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48").unwrap(); let amount = BigUint::from(1000u64); - let approvals = - vec![Approval { owner, spender, token: token.clone(), amount: amount.clone() }]; - let encoded_approvals = permit2 - .encode_approvals(approvals) + let (permit, _) = permit2 + .get_permit(&spender, &owner, &token, &amount) .unwrap(); - assert_eq!(encoded_approvals.len(), 1, "Expected 1 encoded approval"); - - let encoded = &encoded_approvals[0]; - - // Remove prefix and owner (first 64 bytes) and signature (last 65 bytes) - let permit_single_encoded = &encoded[64..encoded.len() - 65]; - - let decoded_permit_single = PermitSingle::abi_decode(permit_single_encoded, false) - .expect("Failed to decode PermitSingle"); let expected_details = PermitDetails { token: bytes_to_address(&token).unwrap(), @@ -263,7 +241,7 @@ mod tests { }; assert_eq!( - decoded_permit_single, expected_permit_single, + permit, expected_permit_single, "Decoded PermitSingle does not match expected values" ); } @@ -309,18 +287,13 @@ mod tests { assert!(receipt.status(), "Approve transaction failed"); let spender = Bytes::from_str("0xba12222222228d8ba445958a75a0704d566bf2c8").unwrap(); - let approvals = vec![Approval { - owner: anvil_account.clone(), - spender: spender.clone(), - token: token.clone(), - amount: amount.clone(), - }]; - let encoded_approvals = permit2 - .encode_approvals(approvals) + let (permit, signature) = permit2 + .get_permit(&spender, &anvil_account, &token, &amount) .unwrap(); - - let encoded = &encoded_approvals[0]; + let encoded = + (bytes_to_address(&anvil_account).unwrap(), permit, signature.as_bytes().to_vec()) + .abi_encode(); let function_signature = "permit(address,((address,uint160,uint48,uint48),address,uint256),bytes)"; diff --git a/src/encoding/mod.rs b/src/encoding/mod.rs index 495a30a..ef2afaa 100644 --- a/src/encoding/mod.rs +++ b/src/encoding/mod.rs @@ -5,4 +5,3 @@ mod models; mod router_encoder; mod strategy_encoder; mod swap_encoder; -mod user_approvals_manager; diff --git a/src/encoding/router_encoder.rs b/src/encoding/router_encoder.rs index be6d1d5..8136af6 100644 --- a/src/encoding/router_encoder.rs +++ b/src/encoding/router_encoder.rs @@ -2,11 +2,10 @@ use crate::encoding::{ errors::EncodingError, models::{Solution, Transaction}, strategy_encoder::StrategySelector, - user_approvals_manager::UserApprovalsManager, }; #[allow(dead_code)] -pub trait RouterEncoder { +pub trait RouterEncoder { fn encode_router_calldata( &self, solutions: Vec, diff --git a/src/encoding/user_approvals_manager.rs b/src/encoding/user_approvals_manager.rs deleted file mode 100644 index 773e048..0000000 --- a/src/encoding/user_approvals_manager.rs +++ /dev/null @@ -1,17 +0,0 @@ -use num_bigint::BigUint; -use tycho_core::Bytes; - -use crate::encoding::errors::EncodingError; - -#[allow(dead_code)] -pub struct Approval { - pub spender: Bytes, - pub owner: Bytes, - pub token: Bytes, - pub amount: BigUint, -} - -pub trait UserApprovalsManager { - #[allow(dead_code)] - fn encode_approvals(&self, approvals: Vec) -> Result>, EncodingError>; -}