feat: Don't sign permit2 objects

We don't want to be responsible for holding private keys -> the user is the one that should do this outside of tycho-execution

Done:
- Remove signature from EncodedSolution
- Introduce UserTransferType and pass that everywhere instead of is_permit2_active and token_in_already_in_router
- Remove signing from permit2. Added it to the encoding_utils.rs only
- Mark encode_full_calldata as deprecated
- Backwards compatibility: still accept a signer for the encode_full_calldata case
- Update all tests

Took 2 hours 10 minutes


Took 13 minutes
This commit is contained in:
Diana Carvalho
2025-05-23 18:22:19 +01:00
parent cdb67f742f
commit c62af2f232
11 changed files with 512 additions and 352 deletions

View File

@@ -7,20 +7,17 @@ use tycho_common::{
}; };
use tycho_execution::encoding::{ use tycho_execution::encoding::{
evm::encoder_builders::TychoRouterEncoderBuilder, evm::encoder_builders::TychoRouterEncoderBuilder,
models::{Solution, Swap}, models::{Solution, Swap, UserTransferType},
}; };
fn main() { fn main() {
// Setup variables
let swapper_pk =
"0x123456789abcdef123456789abcdef123456789abcdef123456789abcdef1234".to_string();
let user_address = Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2") let user_address = Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2")
.expect("Failed to create user address"); .expect("Failed to create user address");
// Initialize the encoder // Initialize the encoder
let encoder = TychoRouterEncoderBuilder::new() let encoder = TychoRouterEncoderBuilder::new()
.chain(Chain::Ethereum) .chain(Chain::Ethereum)
.swapper_pk(swapper_pk) .user_transfer_type(UserTransferType::TransferFrom)
.build() .build()
.expect("Failed to build encoder"); .expect("Failed to build encoder");

View File

@@ -3,23 +3,23 @@ test_single_encoding_strategy_ekubo:5c4b639c000000000000000000000000000000000000
test_uniswap_v3_uniswap_v3:e21dd0d30000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed000000692e234dae75c793f67a35089c9d99245e1c58470b2260fac5e5542a773aa44fbcfedf7c193bc2c599a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc299ac8ca7087fa4a2a1fb6357269965a2014abc35010100000000000000000000 test_uniswap_v3_uniswap_v3:e21dd0d30000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed000000692e234dae75c793f67a35089c9d99245e1c58470b2260fac5e5542a773aa44fbcfedf7c193bc2c599a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc299ac8ca7087fa4a2a1fb6357269965a2014abc35010100000000000000000000
test_balancer_v2_uniswap_v2:e21dd0d30000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000c80072c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e004375dff511095cc5a197a54140a24efef3a416010000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20102000000000000000000000000000000000000000000000000 test_balancer_v2_uniswap_v2:e21dd0d30000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000c80072c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e004375dff511095cc5a197a54140a24efef3a416010000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20102000000000000000000000000000000000000000000000000
test_sequential_swap_strategy_encoder_no_permit2:e21dd0d30000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20102000000000000000000000000000000000000000000000000 test_sequential_swap_strategy_encoder_no_permit2:e21dd0d30000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20102000000000000000000000000000000000000000000000000
test_single_encoding_strategy_usv4_grouped_swap:30ace1b1000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000005064ff624d54346285543f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000000000000000000000000000000000006857d9ed00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000683053f500000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041cf25e6401910938ea5c874981fd6a62d202517677c6cde7546d0de7a1047bb7725946110d38bb0011e6ad191a8245b6de439a04fcde4b86284040260300603ae1c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb486982508145454ce325ddbe47a25d4ec3d23119330000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c6982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000000000000000000000000000000000000000 test_single_encoding_strategy_usv4_grouped_swap:30ace1b1000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000005064ff624d54346285543f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000000000000685836b700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006830b0bf00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041ca2855680741a2290342cdb9a3d4bdafffb0f1e62d3b1e8daac2320d342a97525b2d5b482e223d26d1888d7262f6f32c4f1f3a88a143b091f776245f8f4943581b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb486982508145454ce325ddbe47a25d4ec3d23119330000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c6982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000000000000000000000000000000000000000
test_single_encoding_strategy_usv4_eth_out:7c55384600000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f81490b4f29aade000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000000000000000000000000000000000006857d9ed00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000683053f50000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000412e33858dc4899298476636c393b474a6995d3c076b936d46b90cf6ee00adc801687753f6bad7b89f905d818d217bd94cc0936a9838c48bcaabccd6819baa5e031b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007300710001000000f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c00000000000000000000000000 test_single_encoding_strategy_usv4_eth_out:7c55384600000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f81490b4f29aade000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000b2d05e0000000000000000000000000000000000000000000000000000000000685836b700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006830b0bf000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041f568894962d9b1d0d490cad2051cb88c4fa4a1201577c417d01cc55768b4fa1a526ecd9c73611d5d9dad70c5473a625d46e1fca60e0d025dfc2e9146fa28efc41b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007300710001000000f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c00000000000000000000000000
test_sequential_swap_strategy_encoder:51bcc7b60000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006857d9ed00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000683053f500000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000004124f83f5b4802258cc983101d1cec5c5c3a4a6fed53e545bf8d222817cb75f61d133f1b9916cc0431ea05020b9452ecc673e8d0d27dbaf273c1aa8df9f628850e1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20102000000000000000000000000000000000000000000000000 test_sequential_swap_strategy_encoder:51bcc7b60000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000685836b800000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006830b0c000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000004160b51ba1539713798c36fa209145fc28e33627b9f7fa4e971c5f3616d8dc6fd02d17a7f0a787466465bb98e753be08ec07cfd562396c8474dea91b2c8f97a4f11c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20102000000000000000000000000000000000000000000000000
test_single_swap_strategy_encoder_no_permit2:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000058e7926ee858a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 test_single_swap_strategy_encoder_no_permit2:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000058e7926ee858a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000
test_single_swap_strategy_encoder_no_transfer_in:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000058e7926ee858a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000 test_single_swap_strategy_encoder_no_transfer_in:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000058e7926ee858a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000
test_single_encoding_strategy_usv4_eth_in:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000007e0a55d4322a6e93c2379c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006857d9ed00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000683053f500000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000004162924a8458b13d994bef77420a52e2c31998e7c2bb7a595650784e67313cd10767f720f6213b38446a60410060e3b0ee7359fa6b67a1a06395eaed17e1c6522d1c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006cf62849f9a0b5bf2913b396098f7c7019b51a820a00000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330102cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc26982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000000000000000000000000000 test_single_encoding_strategy_usv4_eth_in:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000007e0a55d4322a6e93c2379c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000685836b700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006830b0bf00000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000415b7c694c0ae0b6a7c44a90ad5c409746c3dbc7c63ac7912f31cbc23f383503fe4127378bdfaffbcda64d382a2cc3a2c139f7763f11e4e21ffb5c07fc258aae581b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006cf62849f9a0b5bf2913b396098f7c7019b51a820a00000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330102cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc26982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000000000000000000000000000
test_sequential_strategy_cyclic_swap:51bcc7b60000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ec8f6e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000000000000000000000000000000000006857d9ed00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000683053f500000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000415eaa6f0c1cb7ba5566023dc3eade4139ebd73f9da94bbc8281dfea578b534f4e1e72bca67d25a3286769b1c8f8ec5d437f3e6f373435c356edf0832d6496688f1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f5640010000692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d8000100000000000000000000 test_sequential_strategy_cyclic_swap:51bcc7b60000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ec8f6e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000685836b800000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006830b0c000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041e3b2388523e7a76ff5810f3a1a092627c7a890994a99a0a49ae5175c5c12657d7fb2c5be13ae8849c593ae9246e8f2de334c5977b5a0820e49a0af2ecbfd89b11c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f5640010000692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d8000100000000000000000000
test_single_encoding_strategy_curve_st_eth:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe84000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000691d1499e622d69689cdf9004d05ec547d650ff211eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeae7ab96520de3a18e5e111b5eaab095312d7fe84dc24316b9ae028f1497c275eb9192a3ea0f670220100010002cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000 test_single_encoding_strategy_curve_st_eth:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe84000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000691d1499e622d69689cdf9004d05ec547d650ff211eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeae7ab96520de3a18e5e111b5eaab095312d7fe84dc24316b9ae028f1497c275eb9192a3ea0f670220100010002cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000
test_single_swap_strategy_encoder:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000006d70b85442ed96492800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006857d9ed00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000683053f500000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000004124f83f5b4802258cc983101d1cec5c5c3a4a6fed53e545bf8d222817cb75f61d133f1b9916cc0431ea05020b9452ecc673e8d0d27dbaf273c1aa8df9f628850e1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000 test_single_swap_strategy_encoder:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000006d70b85442ed96492800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000685836b800000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006830b0c000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000004160b51ba1539713798c36fa209145fc28e33627b9f7fa4e971c5f3616d8dc6fd02d17a7f0a787466465bb98e753be08ec07cfd562396c8474dea91b2c8f97a4f11c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000
test_single_encoding_strategy_curve:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000055c08ca52497e2f1534b59e2917bf524d4765257000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000691d1499e622d69689cdf9004d05ec547d650ff21155c08ca52497e2f1534b59e2917bf524d4765257c02aaa39b223fe8d0a0e5c4f27ead9083c756cc277146b0a1d08b6844376df6d9da99ba7f1b19e710201000100cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000 test_single_encoding_strategy_curve:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000055c08ca52497e2f1534b59e2917bf524d4765257000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000691d1499e622d69689cdf9004d05ec547d650ff21155c08ca52497e2f1534b59e2917bf524d4765257c02aaa39b223fe8d0a0e5c4f27ead9083c756cc277146b0a1d08b6844376df6d9da99ba7f1b19e710201000100cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000
test_single_swap_strategy_encoder_unwrap:30ace1b10000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000a2a15d09519be00000000000000000000000000000000000000000000000000000000000006857d9ed00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000683053f500000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000417ce82920975101831860e9074248018ce1908c61639053bf209f22a0c708db2153d31d68c85362e7f149d9c5481145a4feed8f726a3d6f7a7d7efb2aff876faa1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000000000000000000000000000000 test_single_swap_strategy_encoder_unwrap:30ace1b10000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000a2a15d09519be0000000000000000000000000000000000000000000000000000000000000685836b800000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006830b0c000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041bacbb311e4f4bf852ac6ea61807fbfd8ef961f8f5f1b2455fd7dda16851755334c33b522343304998e3e8e48ecfd85c2b123c162ac41c5c6b26ba523a70b6ae71c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000000000000000000000000000000
test_single_swap_strategy_encoder_wrap:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000059fb7d3830e6fc064b00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006857d9ed00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000683053f500000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000004162924a8458b13d994bef77420a52e2c31998e7c2bb7a595650784e67313cd10767f720f6213b38446a60410060e3b0ee7359fa6b67a1a06395eaed17e1c6522d1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000 test_single_swap_strategy_encoder_wrap:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000059fb7d3830e6fc064b00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000685836b800000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006830b0c000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000411b0820a1eb1d1d4e5c2da500396abb4cb864761c1b92fdaaca6cd2a6cedf82f14fe6c9a31bc617912aecdde40626dd12fb45f3a00b55050a90be6ad447a4ec811b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000
test_split_output_cyclic_swap:7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005e703f4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000000000000000000000000000000000006857d9ed00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000683053f50000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000415eaa6f0c1cb7ba5566023dc3eade4139ebd73f9da94bbc8281dfea578b534f4e1e72bca67d25a3286769b1c8f8ec5d437f3e6f373435c356edf0832d6496688f1b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d013950100006e01009999992e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480001f4cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc288e6a0c2ddd26feeb64f039a2c41296fcb3f56400001006e01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d8000100000000000000 test_split_output_cyclic_swap:7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005e703f4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000685836b800000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006830b0c0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041e3b2388523e7a76ff5810f3a1a092627c7a890994a99a0a49ae5175c5c12657d7fb2c5be13ae8849c593ae9246e8f2de334c5977b5a0820e49a0af2ecbfd89b11c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d013950100006e01009999992e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480001f4cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc288e6a0c2ddd26feeb64f039a2c41296fcb3f56400001006e01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d8000100000000000000
test_split_input_cyclic_swap:7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ef619b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000000000000000000000000000000000006857d9ed00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000683053f50000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000415eaa6f0c1cb7ba5566023dc3eade4139ebd73f9da94bbc8281dfea578b534f4e1e72bca67d25a3286769b1c8f8ec5d437f3e6f373435c356edf0832d6496688f1b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139006e00019999992e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f56400100006e00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d80100005701000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2b4e16d0168e52d35cacd2c6185b44281ec28c9dccd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000100000000000000 test_split_input_cyclic_swap:7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ef619b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000685836b800000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006830b0c0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041e3b2388523e7a76ff5810f3a1a092627c7a890994a99a0a49ae5175c5c12657d7fb2c5be13ae8849c593ae9246e8f2de334c5977b5a0820e49a0af2ecbfd89b11c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139006e00019999992e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f56400100006e00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d80100005701000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2b4e16d0168e52d35cacd2c6185b44281ec28c9dccd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000100000000000000
test_split_swap_strategy_encoder:7c5538460000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006857d9ed00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000683053f500000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000004124f83f5b4802258cc983101d1cec5c5c3a4a6fed53e545bf8d222817cb75f61d133f1b9916cc0431ea05020b9452ecc673e8d0d27dbaf273c1aa8df9f628850e1c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000164005700028000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d013950000005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d013950000005702030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fae461ca67b15dc8dc81ce7615e0320da1a9ab8d5cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20101005701030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010100000000000000000000000000000000000000000000000000000000 test_split_swap_strategy_encoder:7c5538460000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000685836b800000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006830b0c000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000004160b51ba1539713798c36fa209145fc28e33627b9f7fa4e971c5f3616d8dc6fd02d17a7f0a787466465bb98e753be08ec07cfd562396c8474dea91b2c8f97a4f11c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000164005700028000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d013950000005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d013950000005702030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fae461ca67b15dc8dc81ce7615e0320da1a9ab8d5cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20101005701030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010100000000000000000000000000000000000000000000000000000000
test_uniswap_v3_curve:e21dd0d30000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed000000691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae460301000102cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000 test_uniswap_v3_curve:e21dd0d30000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed000000691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae460301000102cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000
test_multi_protocol:51bcc7b600000000000000000000000000000000000000000000005150ae84a8cdf000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a2958f36da71a9200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000005150ae84a8cdf00000000000000000000000000000000000000000000000000000000000006857d9ed00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000683053f500000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041dd1ac43cb92f11fdd55f3a6219229c3397db9bde277ebf06b865f90f1505e27322fa280a162761d23ec4269ee0e4ee23f78a56d3d9044a4b328ead78ace55e1f1c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021400525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000072c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e3ede3eca2a72b3aecc820e955b36f38437d01395010200691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae4603010001023ede3eca2a72b3aecc820e955b36f38437d013950071a0cb889707d426a7a386870a03bc70d1b0697598013ede3eca2a72b3aecc820e955b36f38437d01395dac17f958d2ee523a2206206994597c13d831ec7a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000001a36e2eb1c43200000032006cf62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c000000000000000000000000 test_multi_protocol:51bcc7b600000000000000000000000000000000000000000000005150ae84a8cdf000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a2958f36da71a9200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000005150ae84a8cdf0000000000000000000000000000000000000000000000000000000000000685836b800000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006830b0c000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000004148ed139e954654f795a1b25b70a4ec2ed3f14bba64da8eb471af5ec3e816fbcc4f877a1ea3250c279542ba04063b9cef3bd765821765dd03957723a6c5478ab81c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021400525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000072c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e3ede3eca2a72b3aecc820e955b36f38437d01395010200691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae4603010001023ede3eca2a72b3aecc820e955b36f38437d013950071a0cb889707d426a7a386870a03bc70d1b0697598013ede3eca2a72b3aecc820e955b36f38437d01395dac17f958d2ee523a2206206994597c13d831ec7a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000001a36e2eb1c43200000032006cf62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c000000000000000000000000
test_encode_balancer_v2:c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2ba100000625a3754423978a60c9317c58a424e3d5c6ee304399dbdb9c8ef030ab642b10820db8f560002000000000000000000141d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e0102 test_encode_balancer_v2:c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2ba100000625a3754423978a60c9317c58a424e3d5c6ee304399dbdb9c8ef030ab642b10820db8f560002000000000000000000141d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e0102
test_ekubo_encode_swap_multi:01ca4f73fe97d0b987a0d12b39bbd562c779bab6f60000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4851d02a5948496a67827242eabc5725531342527c000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000001a36e2eb1c43200000032 test_ekubo_encode_swap_multi:01ca4f73fe97d0b987a0d12b39bbd562c779bab6f60000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4851d02a5948496a67827242eabc5725531342527c000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000001a36e2eb1c43200000032
test_encode_uniswap_v4_sequential_swap:4c9edd5852cd905f086c759e8383e09bff1e68b32260fac5e5542a773aa44fbcfedf7c193bc2c5990101cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2dac17f958d2ee523a2206206994597c13d831ec70000640000012260fac5e5542a773aa44fbcfedf7c193bc2c599000bb800003c test_encode_uniswap_v4_sequential_swap:4c9edd5852cd905f086c759e8383e09bff1e68b32260fac5e5542a773aa44fbcfedf7c193bc2c5990101cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2dac17f958d2ee523a2206206994597c13d831ec70000640000012260fac5e5542a773aa44fbcfedf7c193bc2c599000bb800003c

View File

@@ -1,5 +1,10 @@
use std::io::{self, Read}; use std::{
io::{self, Read},
str::FromStr,
};
use alloy::signers::local::PrivateKeySigner;
use alloy_primitives::B256;
use alloy_sol_types::SolValue; use alloy_sol_types::SolValue;
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
use tycho_common::{hex_bytes::Bytes, models::Chain}; use tycho_common::{hex_bytes::Bytes, models::Chain};
@@ -8,7 +13,7 @@ use tycho_execution::encoding::{
approvals::permit2::PermitSingle, approvals::permit2::PermitSingle,
encoder_builders::{TychoExecutorEncoderBuilder, TychoRouterEncoderBuilder}, encoder_builders::{TychoExecutorEncoderBuilder, TychoRouterEncoderBuilder},
}, },
models::Solution, models::{Solution, UserTransferType},
tycho_encoder::TychoEncoder, tycho_encoder::TychoEncoder,
}; };
@@ -56,7 +61,7 @@ pub struct Cli {
#[arg(short, long)] #[arg(short, long)]
swapper_pk: Option<String>, swapper_pk: Option<String>,
#[arg(short, long)] #[arg(short, long)]
token_in_already_in_router: Option<bool>, user_transfer_type: Option<UserTransferType>,
} }
#[derive(Subcommand)] #[derive(Subcommand)]
@@ -91,10 +96,11 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
builder = builder.router_address(router_address); builder = builder.router_address(router_address);
} }
if let Some(swapper_pk) = cli.swapper_pk { if let Some(swapper_pk) = cli.swapper_pk {
builder = builder.swapper_pk(swapper_pk); let pk = B256::from_str(&swapper_pk)?;
builder = builder.signer(PrivateKeySigner::from_bytes(&pk)?);
} }
if let Some(token_in_already_in_router) = cli.token_in_already_in_router { if let Some(user_transfer_type) = cli.user_transfer_type {
builder = builder.token_in_already_in_router(token_in_already_in_router); builder = builder.user_transfer_type(user_transfer_type);
} }
builder.build()? builder.build()?
} }
@@ -111,17 +117,13 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
"n_tokens": format!("{}", &encoded_solutions[0].n_tokens), "n_tokens": format!("{}", &encoded_solutions[0].n_tokens),
"permit": match encoded_solutions[0].permit.as_ref() { "permit": match encoded_solutions[0].permit.as_ref() {
Some(permit) => { Some(permit) => {
match PermitSingle::try_from(permit.clone()) { match PermitSingle::try_from(permit) {
Ok(sol_permit) => format!("0x{}", hex::encode(sol_permit.abi_encode())), Ok(sol_permit) => format!("0x{}", hex::encode(sol_permit.abi_encode())),
Err(_) => String::new(), // or log or panic or whatever fallback Err(_) => String::new(),
} }
} }
None => String::new(), None => String::new(),
}, },
"signature": encoded_solutions[0].signature
.as_ref()
.map(|signature| format!("0x{}", hex::encode(signature)))
.unwrap_or_else(String::new),
}); });
// Output the encoded result as JSON to stdout // Output the encoded result as JSON to stdout
println!( println!(

View File

@@ -4,11 +4,9 @@ use alloy::{
primitives::{aliases::U48, Address, Bytes as AlloyBytes, TxKind, U160, U256}, primitives::{aliases::U48, Address, Bytes as AlloyBytes, TxKind, U160, U256},
providers::{Provider, RootProvider}, providers::{Provider, RootProvider},
rpc::types::{TransactionInput, TransactionRequest}, rpc::types::{TransactionInput, TransactionRequest},
signers::{local::PrivateKeySigner, SignerSync},
transports::BoxTransport, transports::BoxTransport,
}; };
use alloy_primitives::{PrimitiveSignature as Signature, B256}; use alloy_sol_types::{sol, SolValue};
use alloy_sol_types::{eip712_domain, sol, SolStruct, SolValue};
use chrono::Utc; use chrono::Utc;
use num_bigint::BigUint; use num_bigint::BigUint;
use tokio::{ use tokio::{
@@ -24,7 +22,6 @@ use crate::encoding::{
utils::{biguint_to_u256, bytes_to_address, get_client, get_runtime}, utils::{biguint_to_u256, bytes_to_address, get_client, get_runtime},
}, },
models, models,
models::Chain,
}; };
/// Struct for managing Permit2 operations, including encoding approvals and fetching allowance /// Struct for managing Permit2 operations, including encoding approvals and fetching allowance
@@ -33,8 +30,6 @@ use crate::encoding::{
pub struct Permit2 { pub struct Permit2 {
address: Address, address: Address,
client: Arc<RootProvider<BoxTransport>>, client: Arc<RootProvider<BoxTransport>>,
signer: PrivateKeySigner,
chain_id: u64,
runtime_handle: Handle, runtime_handle: Handle,
// Store the runtime to prevent it from being dropped before use. // Store the runtime to prevent it from being dropped before use.
// This is required since tycho-execution does not have a pre-existing runtime. // This is required since tycho-execution does not have a pre-existing runtime.
@@ -69,10 +64,10 @@ sol! {
} }
} }
impl TryFrom<PermitSingle> for models::PermitSingle { impl TryFrom<&PermitSingle> for models::PermitSingle {
type Error = EncodingError; type Error = EncodingError;
fn try_from(sol: PermitSingle) -> Result<Self, EncodingError> { fn try_from(sol: &PermitSingle) -> Result<Self, EncodingError> {
Ok(models::PermitSingle { Ok(models::PermitSingle {
details: models::PermitDetails { details: models::PermitDetails {
token: Bytes::from(sol.details.token.to_vec()), token: Bytes::from(sol.details.token.to_vec()),
@@ -90,10 +85,10 @@ impl TryFrom<PermitSingle> for models::PermitSingle {
} }
} }
impl TryFrom<models::PermitSingle> for PermitSingle { impl TryFrom<&models::PermitSingle> for PermitSingle {
type Error = EncodingError; type Error = EncodingError;
fn try_from(p: models::PermitSingle) -> Result<Self, EncodingError> { fn try_from(p: &models::PermitSingle) -> Result<Self, EncodingError> {
Ok(PermitSingle { Ok(PermitSingle {
details: PermitDetails { details: PermitDetails {
token: bytes_to_address(&p.details.token)?, token: bytes_to_address(&p.details.token)?,
@@ -108,22 +103,14 @@ impl TryFrom<models::PermitSingle> for PermitSingle {
} }
impl Permit2 { impl Permit2 {
pub fn new(swapper_pk: String, chain: Chain) -> Result<Self, EncodingError> { pub fn new() -> Result<Self, EncodingError> {
let (handle, runtime) = get_runtime()?; let (handle, runtime) = get_runtime()?;
let client = block_in_place(|| handle.block_on(get_client()))?; let client = block_in_place(|| handle.block_on(get_client()))?;
let pk = B256::from_str(&swapper_pk).map_err(|_| {
EncodingError::FatalError("Failed to convert swapper private key to B256".to_string())
})?;
let signer = PrivateKeySigner::from_bytes(&pk).map_err(|_| {
EncodingError::FatalError("Failed to create signer from private key".to_string())
})?;
Ok(Self { Ok(Self {
address: Address::from_str("0x000000000022D473030F116dDEE9F6B43aC78BA3") address: Address::from_str("0x000000000022D473030F116dDEE9F6B43aC78BA3")
.map_err(|_| EncodingError::FatalError("Permit2 address not valid".to_string()))?, .map_err(|_| EncodingError::FatalError("Permit2 address not valid".to_string()))?,
client, client,
runtime_handle: handle, runtime_handle: handle,
signer,
chain_id: chain.id,
runtime, runtime,
}) })
} }
@@ -169,7 +156,7 @@ impl Permit2 {
owner: &Bytes, owner: &Bytes,
token: &Bytes, token: &Bytes,
amount: &BigUint, amount: &BigUint,
) -> Result<(models::PermitSingle, Signature), EncodingError> { ) -> Result<models::PermitSingle, EncodingError> {
let current_time = Utc::now() let current_time = Utc::now()
.naive_utc() .naive_utc()
.and_utc() .and_utc()
@@ -188,21 +175,7 @@ impl Permit2 {
sigDeadline: sig_deadline, sigDeadline: sig_deadline,
}; };
let domain = eip712_domain! { Ok(models::PermitSingle::try_from(&permit_single)?)
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((models::PermitSingle::try_from(permit_single)?, signature))
} }
} }
@@ -210,11 +183,13 @@ impl Permit2 {
mod tests { mod tests {
use std::str::FromStr; use std::str::FromStr;
use alloy_primitives::Uint; use alloy::signers::local::PrivateKeySigner;
use alloy_primitives::{Uint, B256};
use num_bigint::BigUint; use num_bigint::BigUint;
use tycho_common::models::Chain as TychoCommonChain; use tycho_common::models::Chain as TychoCommonChain;
use super::*; use super::*;
use crate::encoding::{evm::encoding_utils::sign_permit, models::Chain};
// These two implementations are to avoid comparing the expiration and sig_deadline fields // These two implementations are to avoid comparing the expiration and sig_deadline fields
// because they are timestamps // because they are timestamps
@@ -253,9 +228,7 @@ mod tests {
#[test] #[test]
fn test_get_existing_allowance() { fn test_get_existing_allowance() {
let swapper_pk = let manager = Permit2::new().unwrap();
"4c0883a69102937d6231471b5dbb6204fe512961708279feb1be6ae5538da033".to_string();
let manager = Permit2::new(swapper_pk, eth_chain()).unwrap();
let token = Bytes::from_str("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48").unwrap(); let token = Bytes::from_str("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48").unwrap();
let owner = Bytes::from_str("0x2c6a3cd97c6283b95ac8c5a4459ebb0d5fd404f4").unwrap(); let owner = Bytes::from_str("0x2c6a3cd97c6283b95ac8c5a4459ebb0d5fd404f4").unwrap();
@@ -272,17 +245,14 @@ mod tests {
#[test] #[test]
fn test_get_permit() { fn test_get_permit() {
// Set up a mock private key for signing let permit2 = Permit2::new().expect("Failed to create Permit2");
let private_key =
"4c0883a69102937d6231471b5dbb6204fe512961708279feb1be6ae5538da033".to_string();
let permit2 = Permit2::new(private_key, eth_chain()).expect("Failed to create Permit2");
let owner = Bytes::from_str("0x2c6a3cd97c6283b95ac8c5a4459ebb0d5fd404f4").unwrap(); let owner = Bytes::from_str("0x2c6a3cd97c6283b95ac8c5a4459ebb0d5fd404f4").unwrap();
let spender = Bytes::from_str("0xba12222222228d8ba445958a75a0704d566bf2c8").unwrap(); let spender = Bytes::from_str("0xba12222222228d8ba445958a75a0704d566bf2c8").unwrap();
let token = Bytes::from_str("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48").unwrap(); let token = Bytes::from_str("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48").unwrap();
let amount = BigUint::from(1000u64); let amount = BigUint::from(1000u64);
let (permit, _) = permit2 let permit = permit2
.get_permit(&spender, &owner, &token, &amount) .get_permit(&spender, &owner, &token, &amount)
.unwrap(); .unwrap();
@@ -315,8 +285,19 @@ mod tests {
let anvil_private_key = let anvil_private_key =
"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80".to_string(); "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80".to_string();
let permit2 = let pk = B256::from_str(&anvil_private_key)
Permit2::new(anvil_private_key, eth_chain()).expect("Failed to create Permit2"); .map_err(|_| {
EncodingError::FatalError(
"Failed to convert swapper private key to B256".to_string(),
)
})
.unwrap();
let signer = PrivateKeySigner::from_bytes(&pk)
.map_err(|_| {
EncodingError::FatalError("Failed to create signer from private key".to_string())
})
.unwrap();
let permit2 = Permit2::new().expect("Failed to create Permit2");
let token = Bytes::from_str("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48").unwrap(); let token = Bytes::from_str("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48").unwrap();
let amount = BigUint::from(1000u64); let amount = BigUint::from(1000u64);
@@ -346,11 +327,13 @@ mod tests {
let spender = Bytes::from_str("0xba12222222228d8ba445958a75a0704d566bf2c8").unwrap(); let spender = Bytes::from_str("0xba12222222228d8ba445958a75a0704d566bf2c8").unwrap();
let (permit, signature) = permit2 let permit = permit2
.get_permit(&spender, &anvil_account, &token, &amount) .get_permit(&spender, &anvil_account, &token, &amount)
.unwrap(); .unwrap();
let sol_permit: PermitSingle = let sol_permit: PermitSingle =
PermitSingle::try_from(permit).expect("Failed to convert to PermitSingle"); PermitSingle::try_from(&permit).expect("Failed to convert to PermitSingle");
let signature = sign_permit(eth_chain().id, &permit, signer).unwrap();
let encoded = let encoded =
(bytes_to_address(&anvil_account).unwrap(), sol_permit, signature.as_bytes().to_vec()) (bytes_to_address(&anvil_account).unwrap(), sol_permit, signature.as_bytes().to_vec())
.abi_encode(); .abi_encode();

View File

@@ -1,5 +1,6 @@
use std::collections::HashMap; use std::collections::HashMap;
use alloy::signers::local::PrivateKeySigner;
use tycho_common::{models::Chain as TychoCommonChain, Bytes}; use tycho_common::{models::Chain as TychoCommonChain, Bytes};
use crate::encoding::{ use crate::encoding::{
@@ -9,7 +10,7 @@ use crate::encoding::{
swap_encoder::swap_encoder_registry::SwapEncoderRegistry, swap_encoder::swap_encoder_registry::SwapEncoderRegistry,
tycho_encoders::{TychoExecutorEncoder, TychoRouterEncoder}, tycho_encoders::{TychoExecutorEncoder, TychoRouterEncoder},
}, },
models::Chain, models::{Chain, UserTransferType},
tycho_encoder::TychoEncoder, tycho_encoder::TychoEncoder,
}; };
@@ -17,11 +18,11 @@ use crate::encoding::{
/// ///
/// This struct allows setting a chain and strategy encoder before building the final encoder. /// This struct allows setting a chain and strategy encoder before building the final encoder.
pub struct TychoRouterEncoderBuilder { pub struct TychoRouterEncoderBuilder {
swapper_pk: Option<String>,
chain: Option<Chain>, chain: Option<Chain>,
user_transfer_type: Option<UserTransferType>,
executors_file_path: Option<String>, executors_file_path: Option<String>,
router_address: Option<Bytes>, router_address: Option<Bytes>,
token_in_already_in_router: Option<bool>, signer: Option<PrivateKeySigner>,
} }
impl Default for TychoRouterEncoderBuilder { impl Default for TychoRouterEncoderBuilder {
@@ -33,11 +34,11 @@ impl Default for TychoRouterEncoderBuilder {
impl TychoRouterEncoderBuilder { impl TychoRouterEncoderBuilder {
pub fn new() -> Self { pub fn new() -> Self {
TychoRouterEncoderBuilder { TychoRouterEncoderBuilder {
swapper_pk: None,
chain: None, chain: None,
executors_file_path: None, executors_file_path: None,
router_address: None, router_address: None,
token_in_already_in_router: None, signer: None,
user_transfer_type: None,
} }
} }
pub fn chain(mut self, chain: TychoCommonChain) -> Self { pub fn chain(mut self, chain: TychoCommonChain) -> Self {
@@ -45,6 +46,11 @@ impl TychoRouterEncoderBuilder {
self self
} }
pub fn user_transfer_type(mut self, user_transfer_type: UserTransferType) -> Self {
self.user_transfer_type = Some(user_transfer_type);
self
}
/// Sets the `executors_file_path` manually. /// Sets the `executors_file_path` manually.
/// If it's not set, the default path will be used (config/executor_addresses.json) /// If it's not set, the default path will be used (config/executor_addresses.json)
pub fn executors_file_path(mut self, executors_file_path: String) -> Self { pub fn executors_file_path(mut self, executors_file_path: String) -> Self {
@@ -59,25 +65,15 @@ impl TychoRouterEncoderBuilder {
self self
} }
pub fn swapper_pk(mut self, swapper_pk: String) -> Self { pub fn signer(mut self, signer: PrivateKeySigner) -> Self {
self.swapper_pk = Some(swapper_pk); self.signer = Some(signer);
self
}
// Sets the `token_in_already_in_router` flag.
// If set to true, the encoder will assume that the token in is already in the router.
// WARNING: this is an advanced feature and should be used with caution. Make sure you have
// checks to make sure that your tokens won't be lost. The Router is not considered safe to hold
// tokens, so if this is not done within the same transaction you will lose your tokens.
pub fn token_in_already_in_router(mut self, token_in_already_in_router: bool) -> Self {
self.token_in_already_in_router = Some(token_in_already_in_router);
self self
} }
/// Builds the `TychoRouterEncoder` instance using the configured chain. /// Builds the `TychoRouterEncoder` instance using the configured chain.
/// Returns an error if either the chain has not been set. /// Returns an error if either the chain has not been set.
pub fn build(self) -> Result<Box<dyn TychoEncoder>, EncodingError> { pub fn build(self) -> Result<Box<dyn TychoEncoder>, EncodingError> {
if let Some(chain) = self.chain { if let (Some(chain), Some(user_transfer_type)) = (self.chain, self.user_transfer_type) {
let tycho_router_address; let tycho_router_address;
if let Some(address) = self.router_address { if let Some(address) = self.router_address {
tycho_router_address = address; tycho_router_address = address;
@@ -98,14 +94,14 @@ impl TychoRouterEncoderBuilder {
Ok(Box::new(TychoRouterEncoder::new( Ok(Box::new(TychoRouterEncoder::new(
chain, chain,
swap_encoder_registry, swap_encoder_registry,
self.swapper_pk,
tycho_router_address, tycho_router_address,
self.token_in_already_in_router user_transfer_type,
.unwrap_or(false), self.signer,
)?)) )?))
} else { } else {
Err(EncodingError::FatalError( Err(EncodingError::FatalError(
"Please set the chain and router address before building the encoder".to_string(), "Please set the chain and user transfer type before building the encoder"
.to_string(),
)) ))
} }
} }

View File

@@ -1,5 +1,11 @@
use alloy_primitives::{Keccak256, U256}; use std::str::FromStr;
use alloy_sol_types::SolValue;
use alloy::{
primitives::U256,
signers::{local::PrivateKeySigner, Signature, SignerSync},
};
use alloy_primitives::{Address, Keccak256};
use alloy_sol_types::{eip712_domain, SolStruct, SolValue};
use num_bigint::BigUint; use num_bigint::BigUint;
use tycho_common::Bytes; use tycho_common::Bytes;
@@ -9,7 +15,8 @@ use crate::encoding::{
approvals::permit2::PermitSingle, approvals::permit2::PermitSingle,
utils::{biguint_to_u256, bytes_to_address}, utils::{biguint_to_u256, bytes_to_address},
}, },
models::{EncodedSolution, NativeAction, Solution, Transaction}, models,
models::{EncodedSolution, NativeAction, Solution, Transaction, UserTransferType},
}; };
/// Encodes the input data for a function call to the given function selector. /// Encodes the input data for a function call to the given function selector.
@@ -56,6 +63,7 @@ pub fn encode_input(selector: &str, mut encoded_args: Vec<u8>) -> Vec<u8> {
/// their own encoding logic** to ensure: /// their own encoding logic** to ensure:
/// - Full control of parameters passed to the router. /// - Full control of parameters passed to the router.
/// - Proper validation and setting of critical inputs such as `minAmountOut`. /// - Proper validation and setting of critical inputs such as `minAmountOut`.
/// - Signing of permit2 objects.
/// ///
/// While Tycho is responsible for encoding the swap paths themselves, the input arguments /// While Tycho is responsible for encoding the swap paths themselves, the input arguments
/// to the router's methods act as **guardrails** for on-chain execution safety. /// to the router's methods act as **guardrails** for on-chain execution safety.
@@ -87,10 +95,12 @@ pub fn encode_input(selector: &str, mut encoded_args: Vec<u8>) -> Vec<u8> {
/// - Returns `EncodingError::FatalError` if the selector is unsupported or required fields (e.g., /// - Returns `EncodingError::FatalError` if the selector is unsupported or required fields (e.g.,
/// permit or signature) are missing. /// permit or signature) are missing.
pub fn encode_tycho_router_call( pub fn encode_tycho_router_call(
chain_id: u64,
encoded_solution: EncodedSolution, encoded_solution: EncodedSolution,
solution: &Solution, solution: &Solution,
token_in_already_in_router: bool, user_transfer_type: UserTransferType,
native_address: Bytes, native_address: Bytes,
signer: Option<PrivateKeySigner>,
) -> Result<Transaction, EncodingError> { ) -> Result<Transaction, EncodingError> {
let (mut unwrap, mut wrap) = (false, false); let (mut unwrap, mut wrap) = (false, false);
if let Some(action) = solution.native_action.clone() { if let Some(action) = solution.native_action.clone() {
@@ -106,23 +116,23 @@ pub fn encode_tycho_router_call(
let checked_token = bytes_to_address(&solution.checked_token)?; let checked_token = bytes_to_address(&solution.checked_token)?;
let receiver = bytes_to_address(&solution.receiver)?; let receiver = bytes_to_address(&solution.receiver)?;
let n_tokens = U256::from(encoded_solution.n_tokens); let n_tokens = U256::from(encoded_solution.n_tokens);
let permit = if let Some(p) = encoded_solution.permit { let (permit, signature) = if let Some(p) = encoded_solution.permit {
Some( let permit = Some(
PermitSingle::try_from(p) PermitSingle::try_from(&p)
.map_err(|_| EncodingError::InvalidInput("Invalid permit".to_string()))?, .map_err(|_| EncodingError::InvalidInput("Invalid permit".to_string()))?,
) );
let signer = signer
.ok_or(EncodingError::FatalError("Signer must be set to use permit2".to_string()))?;
let signature = sign_permit(chain_id, &p, signer)?;
(permit, signature.as_bytes().to_vec())
} else { } else {
None (None, vec![])
}; };
let method_calldata = if encoded_solution let method_calldata = if encoded_solution
.selector .selector
.contains("singleSwapPermit2") .contains("singleSwapPermit2")
{ {
let sig = encoded_solution
.signature
.ok_or(EncodingError::FatalError("Signature must be set to use permit2".to_string()))?;
println!("sig {:}", hex::encode(&sig));
( (
given_amount, given_amount,
given_token, given_token,
@@ -134,7 +144,7 @@ pub fn encode_tycho_router_call(
permit.ok_or(EncodingError::FatalError( permit.ok_or(EncodingError::FatalError(
"permit2 object must be set to use permit2".to_string(), "permit2 object must be set to use permit2".to_string(),
))?, ))?,
sig, signature,
encoded_solution.swaps, encoded_solution.swaps,
) )
.abi_encode() .abi_encode()
@@ -150,7 +160,7 @@ pub fn encode_tycho_router_call(
wrap, wrap,
unwrap, unwrap,
receiver, receiver,
!token_in_already_in_router, user_transfer_type == UserTransferType::TransferFrom,
encoded_solution.swaps, encoded_solution.swaps,
) )
.abi_encode() .abi_encode()
@@ -169,11 +179,7 @@ pub fn encode_tycho_router_call(
permit.ok_or(EncodingError::FatalError( permit.ok_or(EncodingError::FatalError(
"permit2 object must be set to use permit2".to_string(), "permit2 object must be set to use permit2".to_string(),
))?, ))?,
encoded_solution signature,
.signature
.ok_or(EncodingError::FatalError(
"Signature must be set to use permit2".to_string(),
))?,
encoded_solution.swaps, encoded_solution.swaps,
) )
.abi_encode() .abi_encode()
@@ -189,7 +195,7 @@ pub fn encode_tycho_router_call(
wrap, wrap,
unwrap, unwrap,
receiver, receiver,
!token_in_already_in_router, user_transfer_type == UserTransferType::TransferFrom,
encoded_solution.swaps, encoded_solution.swaps,
) )
.abi_encode() .abi_encode()
@@ -209,11 +215,7 @@ pub fn encode_tycho_router_call(
permit.ok_or(EncodingError::FatalError( permit.ok_or(EncodingError::FatalError(
"permit2 object must be set to use permit2".to_string(), "permit2 object must be set to use permit2".to_string(),
))?, ))?,
encoded_solution signature,
.signature
.ok_or(EncodingError::FatalError(
"Signature must be set to use permit2".to_string(),
))?,
encoded_solution.swaps, encoded_solution.swaps,
) )
.abi_encode() .abi_encode()
@@ -230,7 +232,7 @@ pub fn encode_tycho_router_call(
unwrap, unwrap,
n_tokens, n_tokens,
receiver, receiver,
!token_in_already_in_router, user_transfer_type == UserTransferType::TransferFrom,
encoded_solution.swaps, encoded_solution.swaps,
) )
.abi_encode() .abi_encode()
@@ -246,3 +248,33 @@ pub fn encode_tycho_router_call(
}; };
Ok(Transaction { to: encoded_solution.interacting_with, value, data: contract_interaction }) Ok(Transaction { to: encoded_solution.interacting_with, value, data: contract_interaction })
} }
/// Signs a Permit2 `PermitSingle` struct using the EIP-712 signing scheme.
///
/// This function constructs an EIP-712 domain specific to the Permit2 contract and computes the
/// hash of the provided `PermitSingle`. It then uses the given `PrivateKeySigner` to produce
/// a cryptographic signature of the permit.
///
/// # Warning
/// This is only an **example implementation** provided for reference purposes.
/// **Do not rely on this in production.** You should implement your own version.
pub fn sign_permit(
chain_id: u64,
permit_single: &models::PermitSingle,
signer: PrivateKeySigner,
) -> Result<Signature, EncodingError> {
let permit2_address = Address::from_str("0x000000000022D473030F116dDEE9F6B43aC78BA3")
.map_err(|_| EncodingError::FatalError("Permit2 address not valid".to_string()))?;
let domain = eip712_domain! {
name: "Permit2",
chain_id: chain_id,
verifying_contract: permit2_address,
};
let permit_single: PermitSingle = PermitSingle::try_from(permit_single)?;
let hash = permit_single.eip712_signing_hash(&domain);
signer
.sign_hash_sync(&hash)
.map_err(|e| {
EncodingError::FatalError(format!("Failed to sign permit2 approval with error: {e}"))
})
}

View File

@@ -14,7 +14,7 @@ use crate::encoding::{
swap_encoder::swap_encoder_registry::SwapEncoderRegistry, swap_encoder::swap_encoder_registry::SwapEncoderRegistry,
utils::{get_token_position, percentage_to_uint24, ple_encode}, utils::{get_token_position, percentage_to_uint24, ple_encode},
}, },
models::{Chain, EncodedSolution, EncodingContext, NativeAction, Solution}, models::{Chain, EncodedSolution, EncodingContext, NativeAction, Solution, UserTransferType},
strategy_encoder::StrategyEncoder, strategy_encoder::StrategyEncoder,
swap_encoder::SwapEncoder, swap_encoder::SwapEncoder,
}; };
@@ -38,11 +38,10 @@ impl SingleSwapStrategyEncoder {
pub fn new( pub fn new(
chain: Chain, chain: Chain,
swap_encoder_registry: SwapEncoderRegistry, swap_encoder_registry: SwapEncoderRegistry,
permit_2_active: bool, user_transfer_type: UserTransferType,
router_address: Bytes, router_address: Bytes,
token_in_already_in_router: bool,
) -> Result<Self, EncodingError> { ) -> Result<Self, EncodingError> {
let selector = if permit_2_active { let selector = if user_transfer_type == UserTransferType::TransferFromPermit2 {
"singleSwapPermit2(uint256,address,address,uint256,bool,bool,address,((address,uint160,uint48,uint48),address,uint256),bytes,bytes)" "singleSwapPermit2(uint256,address,address,uint256,bool,bool,address,((address,uint160,uint48,uint48),address,uint256),bytes,bytes)"
} else { } else {
"singleSwap(uint256,address,address,uint256,bool,bool,address,bool,bytes)" "singleSwap(uint256,address,address,uint256,bool,bool,address,bool,bytes)"
@@ -55,7 +54,7 @@ impl SingleSwapStrategyEncoder {
transfer_optimization: TransferOptimization::new( transfer_optimization: TransferOptimization::new(
chain.native_token()?, chain.native_token()?,
chain.wrapped_token()?, chain.wrapped_token()?,
token_in_already_in_router, user_transfer_type,
router_address, router_address,
), ),
}) })
@@ -138,7 +137,6 @@ impl StrategyEncoder for SingleSwapStrategyEncoder {
interacting_with: self.router_address.clone(), interacting_with: self.router_address.clone(),
swaps: swap_data, swaps: swap_data,
permit: None, permit: None,
signature: None,
n_tokens: 0, n_tokens: 0,
}) })
} }
@@ -179,11 +177,10 @@ impl SequentialSwapStrategyEncoder {
pub fn new( pub fn new(
chain: Chain, chain: Chain,
swap_encoder_registry: SwapEncoderRegistry, swap_encoder_registry: SwapEncoderRegistry,
permit_2_active: bool, user_transfer_type: UserTransferType,
router_address: Bytes, router_address: Bytes,
token_in_already_in_router: bool,
) -> Result<Self, EncodingError> { ) -> Result<Self, EncodingError> {
let selector = if permit_2_active { let selector = if user_transfer_type == UserTransferType::TransferFromPermit2 {
"sequentialSwapPermit2(uint256,address,address,uint256,bool,bool,address,((address,uint160,uint48,uint48),address,uint256),bytes,bytes)" "sequentialSwapPermit2(uint256,address,address,uint256,bool,bool,address,((address,uint160,uint48,uint48),address,uint256),bytes,bytes)"
} else { } else {
"sequentialSwap(uint256,address,address,uint256,bool,bool,address,bool,bytes)" "sequentialSwap(uint256,address,address,uint256,bool,bool,address,bool,bytes)"
@@ -199,7 +196,7 @@ impl SequentialSwapStrategyEncoder {
transfer_optimization: TransferOptimization::new( transfer_optimization: TransferOptimization::new(
chain.native_token()?, chain.native_token()?,
chain.wrapped_token()?, chain.wrapped_token()?,
token_in_already_in_router, user_transfer_type,
router_address, router_address,
), ),
}) })
@@ -294,7 +291,6 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder {
selector: self.selector.clone(), selector: self.selector.clone(),
swaps: encoded_swaps, swaps: encoded_swaps,
permit: None, permit: None,
signature: None,
n_tokens: 0, n_tokens: 0,
}) })
} }
@@ -335,11 +331,10 @@ impl SplitSwapStrategyEncoder {
pub fn new( pub fn new(
chain: Chain, chain: Chain,
swap_encoder_registry: SwapEncoderRegistry, swap_encoder_registry: SwapEncoderRegistry,
permit_2_active: bool, user_transfer_type: UserTransferType,
router_address: Bytes, router_address: Bytes,
token_in_already_in_router: bool,
) -> Result<Self, EncodingError> { ) -> Result<Self, EncodingError> {
let selector = if permit_2_active{ let selector = if user_transfer_type == UserTransferType::TransferFromPermit2 {
"splitSwapPermit2(uint256,address,address,uint256,bool,bool,uint256,address,((address,uint160,uint48,uint48),address,uint256),bytes,bytes)" "splitSwapPermit2(uint256,address,address,uint256,bool,bool,uint256,address,((address,uint160,uint48,uint48),address,uint256),bytes,bytes)"
} else { } else {
"splitSwap(uint256,address,address,uint256,bool,bool,uint256,address,bool,bytes)" "splitSwap(uint256,address,address,uint256,bool,bool,uint256,address,bool,bytes)"
@@ -354,7 +349,7 @@ impl SplitSwapStrategyEncoder {
transfer_optimization: TransferOptimization::new( transfer_optimization: TransferOptimization::new(
chain.native_token()?, chain.native_token()?,
chain.wrapped_token()?, chain.wrapped_token()?,
token_in_already_in_router, user_transfer_type,
router_address, router_address,
), ),
}) })
@@ -497,7 +492,6 @@ impl StrategyEncoder for SplitSwapStrategyEncoder {
selector: self.selector.clone(), selector: self.selector.clone(),
swaps: encoded_swaps, swaps: encoded_swaps,
permit: None, permit: None,
signature: None,
n_tokens: tokens_len, n_tokens: tokens_len,
}) })
} }
@@ -516,8 +510,8 @@ impl StrategyEncoder for SplitSwapStrategyEncoder {
mod tests { mod tests {
use std::{collections::HashMap, str::FromStr}; use std::{collections::HashMap, str::FromStr};
use alloy::hex::encode; use alloy::{hex::encode, signers::local::PrivateKeySigner};
use alloy_primitives::{hex, Address, PrimitiveSignature as Signature, U256}; use alloy_primitives::{hex, Address, B256, U256};
use num_bigint::{BigInt, BigUint}; use num_bigint::{BigInt, BigUint};
use tycho_common::{ use tycho_common::{
models::{protocol::ProtocolComponent, Chain as TychoCommonChain}, models::{protocol::ProtocolComponent, Chain as TychoCommonChain},
@@ -555,24 +549,26 @@ mod tests {
Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap() Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap()
} }
fn get_permit( fn get_permit(router_address: Bytes, solution: &Solution) -> PermitSingle {
chain: Chain, let permit2 = Permit2::new().unwrap();
router_address: Bytes, let permit_single = permit2
solution: &Solution,
) -> (PermitSingle, Signature) {
// Set up a mock private key for signing (Alice's pk in our contract tests)
let private_key =
"0x123456789abcdef123456789abcdef123456789abcdef123456789abcdef1234".to_string();
let permit2 = Permit2::new(private_key, chain.clone()).unwrap();
permit2
.get_permit( .get_permit(
&router_address, &router_address,
&solution.sender, &solution.sender,
&solution.given_token, &solution.given_token,
&solution.given_amount, &solution.given_amount,
) )
.unwrap() .unwrap();
permit_single
}
fn get_signer() -> PrivateKeySigner {
// Set up a mock private key for signing (Alice's pk in our contract tests)
let private_key =
"0x123456789abcdef123456789abcdef123456789abcdef123456789abcdef1234".to_string();
let pk = B256::from_str(&private_key).unwrap();
PrivateKeySigner::from_bytes(&pk).unwrap()
} }
mod single { mod single {
@@ -602,9 +598,8 @@ mod tests {
let encoder = SingleSwapStrategyEncoder::new( let encoder = SingleSwapStrategyEncoder::new(
eth_chain(), eth_chain(),
swap_encoder_registry, swap_encoder_registry,
true, UserTransferType::TransferFromPermit2,
router_address(), router_address(),
false,
) )
.unwrap(); .unwrap();
let solution = Solution { let solution = Solution {
@@ -622,11 +617,17 @@ mod tests {
let mut encoded_solution = encoder let mut encoded_solution = encoder
.encode_strategy(solution.clone()) .encode_strategy(solution.clone())
.unwrap(); .unwrap();
let (permit, signature) = get_permit(eth_chain(), router_address(), &solution); let permit = get_permit(router_address(), &solution);
encoded_solution.permit = Some(permit); encoded_solution.permit = Some(permit);
encoded_solution.signature = Some(signature.as_bytes().to_vec());
let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth()) let calldata = encode_tycho_router_call(
eth_chain().id,
encoded_solution,
&solution,
UserTransferType::TransferFromPermit2,
eth(),
Some(get_signer()),
)
.unwrap() .unwrap()
.data; .data;
let expected_min_amount_encoded = let expected_min_amount_encoded =
@@ -690,9 +691,8 @@ mod tests {
let encoder = SingleSwapStrategyEncoder::new( let encoder = SingleSwapStrategyEncoder::new(
eth_chain(), eth_chain(),
swap_encoder_registry, swap_encoder_registry,
false, UserTransferType::TransferFrom,
router_address(), router_address(),
false,
) )
.unwrap(); .unwrap();
let solution = Solution { let solution = Solution {
@@ -710,7 +710,14 @@ mod tests {
let encoded_solution = encoder let encoded_solution = encoder
.encode_strategy(solution.clone()) .encode_strategy(solution.clone())
.unwrap(); .unwrap();
let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth()) let calldata = encode_tycho_router_call(
eth_chain().id,
encoded_solution,
&solution,
UserTransferType::TransferFrom,
eth(),
None,
)
.unwrap() .unwrap()
.data; .data;
let expected_min_amount_encoded = hex::encode(U256::abi_encode(&expected_min_amount)); let expected_min_amount_encoded = hex::encode(U256::abi_encode(&expected_min_amount));
@@ -772,9 +779,8 @@ mod tests {
let encoder = SingleSwapStrategyEncoder::new( let encoder = SingleSwapStrategyEncoder::new(
eth_chain(), eth_chain(),
swap_encoder_registry, swap_encoder_registry,
false, UserTransferType::None,
router_address(), router_address(),
true,
) )
.unwrap(); .unwrap();
let solution = Solution { let solution = Solution {
@@ -792,7 +798,14 @@ mod tests {
let encoded_solution = encoder let encoded_solution = encoder
.encode_strategy(solution.clone()) .encode_strategy(solution.clone())
.unwrap(); .unwrap();
let calldata = encode_tycho_router_call(encoded_solution, &solution, true, eth()) let calldata = encode_tycho_router_call(
eth_chain().id,
encoded_solution,
&solution,
UserTransferType::None,
eth(),
None,
)
.unwrap() .unwrap()
.data; .data;
let expected_min_amount_encoded = hex::encode(U256::abi_encode(&expected_min_amount)); let expected_min_amount_encoded = hex::encode(U256::abi_encode(&expected_min_amount));
@@ -851,9 +864,8 @@ mod tests {
let encoder = SingleSwapStrategyEncoder::new( let encoder = SingleSwapStrategyEncoder::new(
eth_chain(), eth_chain(),
swap_encoder_registry, swap_encoder_registry,
true, UserTransferType::TransferFromPermit2,
router_address(), router_address(),
false,
) )
.unwrap(); .unwrap();
let solution = Solution { let solution = Solution {
@@ -872,11 +884,17 @@ mod tests {
.encode_strategy(solution.clone()) .encode_strategy(solution.clone())
.unwrap(); .unwrap();
let (permit, signature) = get_permit(eth_chain(), router_address(), &solution); let permit = get_permit(router_address(), &solution);
encoded_solution.permit = Some(permit); encoded_solution.permit = Some(permit);
encoded_solution.signature = Some(signature.as_bytes().to_vec());
let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth()) let calldata = encode_tycho_router_call(
eth_chain().id,
encoded_solution,
&solution,
UserTransferType::TransferFromPermit2,
eth(),
Some(get_signer()),
)
.unwrap() .unwrap()
.data; .data;
let hex_calldata = encode(&calldata); let hex_calldata = encode(&calldata);
@@ -905,9 +923,8 @@ mod tests {
let encoder = SingleSwapStrategyEncoder::new( let encoder = SingleSwapStrategyEncoder::new(
eth_chain(), eth_chain(),
swap_encoder_registry, swap_encoder_registry,
true, UserTransferType::TransferFromPermit2,
Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395"), Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395"),
false,
) )
.unwrap(); .unwrap();
let solution = Solution { let solution = Solution {
@@ -926,11 +943,17 @@ mod tests {
.encode_strategy(solution.clone()) .encode_strategy(solution.clone())
.unwrap(); .unwrap();
let (permit, signature) = get_permit(eth_chain(), router_address(), &solution); let permit = get_permit(router_address(), &solution);
encoded_solution.permit = Some(permit); encoded_solution.permit = Some(permit);
encoded_solution.signature = Some(signature.as_bytes().to_vec());
let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth()) let calldata = encode_tycho_router_call(
eth_chain().id,
encoded_solution,
&solution,
UserTransferType::TransferFromPermit2,
eth(),
Some(get_signer()),
)
.unwrap() .unwrap()
.data; .data;
@@ -982,9 +1005,8 @@ mod tests {
let encoder = SequentialSwapStrategyEncoder::new( let encoder = SequentialSwapStrategyEncoder::new(
eth_chain(), eth_chain(),
swap_encoder_registry, swap_encoder_registry,
true, UserTransferType::TransferFromPermit2,
router_address(), router_address(),
false,
) )
.unwrap(); .unwrap();
let solution = Solution { let solution = Solution {
@@ -1002,11 +1024,17 @@ mod tests {
let mut encoded_solution = encoder let mut encoded_solution = encoder
.encode_strategy(solution.clone()) .encode_strategy(solution.clone())
.unwrap(); .unwrap();
let (permit, signature) = get_permit(eth_chain(), router_address(), &solution); let permit = get_permit(router_address(), &solution);
encoded_solution.permit = Some(permit); encoded_solution.permit = Some(permit);
encoded_solution.signature = Some(signature.as_bytes().to_vec());
let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth()) let calldata = encode_tycho_router_call(
eth_chain().id,
encoded_solution,
&solution,
UserTransferType::TransferFromPermit2,
eth(),
Some(get_signer()),
)
.unwrap() .unwrap()
.data; .data;
@@ -1048,9 +1076,8 @@ mod tests {
let encoder = SequentialSwapStrategyEncoder::new( let encoder = SequentialSwapStrategyEncoder::new(
eth_chain(), eth_chain(),
swap_encoder_registry, swap_encoder_registry,
false, UserTransferType::TransferFrom,
router_address(), router_address(),
false,
) )
.unwrap(); .unwrap();
let solution = Solution { let solution = Solution {
@@ -1069,7 +1096,14 @@ mod tests {
.encode_strategy(solution.clone()) .encode_strategy(solution.clone())
.unwrap(); .unwrap();
let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth()) let calldata = encode_tycho_router_call(
eth_chain().id,
encoded_solution,
&solution,
UserTransferType::TransferFrom,
eth(),
None,
)
.unwrap() .unwrap()
.data; .data;
@@ -1170,9 +1204,8 @@ mod tests {
let encoder = SequentialSwapStrategyEncoder::new( let encoder = SequentialSwapStrategyEncoder::new(
eth_chain(), eth_chain(),
swap_encoder_registry, swap_encoder_registry,
true, UserTransferType::TransferFromPermit2,
Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395"), Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395"),
false,
) )
.unwrap(); .unwrap();
@@ -1192,11 +1225,17 @@ mod tests {
let mut encoded_solution = encoder let mut encoded_solution = encoder
.encode_strategy(solution.clone()) .encode_strategy(solution.clone())
.unwrap(); .unwrap();
let (permit, signature) = get_permit(eth_chain(), router_address(), &solution); let permit = get_permit(router_address(), &solution);
encoded_solution.permit = Some(permit); encoded_solution.permit = Some(permit);
encoded_solution.signature = Some(signature.as_bytes().to_vec());
let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth()) let calldata = encode_tycho_router_call(
eth_chain().id,
encoded_solution,
&solution,
UserTransferType::TransferFromPermit2,
eth(),
Some(get_signer()),
)
.unwrap() .unwrap()
.data; .data;
let hex_calldata = hex::encode(&calldata); let hex_calldata = hex::encode(&calldata);
@@ -1292,9 +1331,8 @@ mod tests {
let encoder = SequentialSwapStrategyEncoder::new( let encoder = SequentialSwapStrategyEncoder::new(
eth_chain(), eth_chain(),
swap_encoder_registry, swap_encoder_registry,
false, UserTransferType::TransferFrom,
router_address(), router_address(),
false,
) )
.unwrap(); .unwrap();
let solution = Solution { let solution = Solution {
@@ -1314,7 +1352,14 @@ mod tests {
.encode_strategy(solution.clone()) .encode_strategy(solution.clone())
.unwrap(); .unwrap();
let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth()) let calldata = encode_tycho_router_call(
eth_chain().id,
encoded_solution,
&solution,
UserTransferType::TransferFrom,
eth(),
None,
)
.unwrap() .unwrap()
.data; .data;
@@ -1377,9 +1422,8 @@ mod tests {
let encoder = SequentialSwapStrategyEncoder::new( let encoder = SequentialSwapStrategyEncoder::new(
eth_chain(), eth_chain(),
swap_encoder_registry, swap_encoder_registry,
false, UserTransferType::TransferFrom,
router_address(), router_address(),
false,
) )
.unwrap(); .unwrap();
let solution = Solution { let solution = Solution {
@@ -1399,7 +1443,14 @@ mod tests {
.encode_strategy(solution.clone()) .encode_strategy(solution.clone())
.unwrap(); .unwrap();
let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth()) let calldata = encode_tycho_router_call(
eth_chain().id,
encoded_solution,
&solution,
UserTransferType::TransferFrom,
eth(),
None,
)
.unwrap() .unwrap()
.data; .data;
@@ -1471,9 +1522,8 @@ mod tests {
let encoder = SequentialSwapStrategyEncoder::new( let encoder = SequentialSwapStrategyEncoder::new(
eth_chain(), eth_chain(),
swap_encoder_registry, swap_encoder_registry,
false, UserTransferType::TransferFrom,
router_address(), router_address(),
false,
) )
.unwrap(); .unwrap();
let solution = Solution { let solution = Solution {
@@ -1493,7 +1543,14 @@ mod tests {
.encode_strategy(solution.clone()) .encode_strategy(solution.clone())
.unwrap(); .unwrap();
let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth()) let calldata = encode_tycho_router_call(
eth_chain().id,
encoded_solution,
&solution,
UserTransferType::TransferFrom,
eth(),
None,
)
.unwrap() .unwrap()
.data; .data;
@@ -1541,9 +1598,8 @@ mod tests {
let encoder = SequentialSwapStrategyEncoder::new( let encoder = SequentialSwapStrategyEncoder::new(
eth_chain(), eth_chain(),
swap_encoder_registry, swap_encoder_registry,
false, UserTransferType::TransferFrom,
router_address(), router_address(),
false,
) )
.unwrap(); .unwrap();
let solution = Solution { let solution = Solution {
@@ -1563,7 +1619,14 @@ mod tests {
.encode_strategy(solution.clone()) .encode_strategy(solution.clone())
.unwrap(); .unwrap();
let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth()) let calldata = encode_tycho_router_call(
eth_chain().id,
encoded_solution,
&solution,
UserTransferType::TransferFrom,
eth(),
None,
)
.unwrap() .unwrap()
.data; .data;
@@ -1687,9 +1750,8 @@ mod tests {
let encoder = SequentialSwapStrategyEncoder::new( let encoder = SequentialSwapStrategyEncoder::new(
eth_chain(), eth_chain(),
swap_encoder_registry, swap_encoder_registry,
true, UserTransferType::TransferFromPermit2,
router_address(), router_address(),
false,
) )
.unwrap(); .unwrap();
let solution = Solution { let solution = Solution {
@@ -1714,11 +1776,17 @@ mod tests {
let mut encoded_solution = encoder let mut encoded_solution = encoder
.encode_strategy(solution.clone()) .encode_strategy(solution.clone())
.unwrap(); .unwrap();
let (permit, signature) = get_permit(eth_chain(), router_address(), &solution); let permit = get_permit(router_address(), &solution);
encoded_solution.permit = Some(permit); encoded_solution.permit = Some(permit);
encoded_solution.signature = Some(signature.as_bytes().to_vec());
let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth) let calldata = encode_tycho_router_call(
eth_chain().id,
encoded_solution,
&solution,
UserTransferType::TransferFromPermit2,
eth,
Some(get_signer()),
)
.unwrap() .unwrap()
.data; .data;
@@ -1795,9 +1863,8 @@ mod tests {
let encoder = SplitSwapStrategyEncoder::new( let encoder = SplitSwapStrategyEncoder::new(
eth_chain(), eth_chain(),
swap_encoder_registry, swap_encoder_registry,
true, UserTransferType::TransferFromPermit2,
Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395"), Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395"),
false,
) )
.unwrap(); .unwrap();
let solution = Solution { let solution = Solution {
@@ -1815,11 +1882,17 @@ mod tests {
let mut encoded_solution = encoder let mut encoded_solution = encoder
.encode_strategy(solution.clone()) .encode_strategy(solution.clone())
.unwrap(); .unwrap();
let (permit, signature) = get_permit(eth_chain(), router_address(), &solution); let permit = get_permit(router_address(), &solution);
encoded_solution.permit = Some(permit); encoded_solution.permit = Some(permit);
encoded_solution.signature = Some(signature.as_bytes().to_vec());
let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth()) let calldata = encode_tycho_router_call(
eth_chain().id,
encoded_solution,
&solution,
UserTransferType::TransferFromPermit2,
eth(),
Some(get_signer()),
)
.unwrap() .unwrap()
.data; .data;
@@ -1907,9 +1980,8 @@ mod tests {
let encoder = SplitSwapStrategyEncoder::new( let encoder = SplitSwapStrategyEncoder::new(
eth_chain(), eth_chain(),
swap_encoder_registry, swap_encoder_registry,
true, UserTransferType::TransferFromPermit2,
Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395"), Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395"),
false,
) )
.unwrap(); .unwrap();
@@ -1930,11 +2002,17 @@ mod tests {
let mut encoded_solution = encoder let mut encoded_solution = encoder
.encode_strategy(solution.clone()) .encode_strategy(solution.clone())
.unwrap(); .unwrap();
let (permit, signature) = get_permit(eth_chain(), router_address(), &solution); let permit = get_permit(router_address(), &solution);
encoded_solution.permit = Some(permit); encoded_solution.permit = Some(permit);
encoded_solution.signature = Some(signature.as_bytes().to_vec());
let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth()) let calldata = encode_tycho_router_call(
eth_chain().id,
encoded_solution,
&solution,
UserTransferType::TransferFromPermit2,
eth(),
Some(get_signer()),
)
.unwrap() .unwrap()
.data; .data;
@@ -2071,9 +2149,8 @@ mod tests {
let encoder = SplitSwapStrategyEncoder::new( let encoder = SplitSwapStrategyEncoder::new(
eth_chain(), eth_chain(),
swap_encoder_registry, swap_encoder_registry,
true, UserTransferType::TransferFromPermit2,
Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395"), Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395"),
false,
) )
.unwrap(); .unwrap();
@@ -2094,11 +2171,17 @@ mod tests {
let mut encoded_solution = encoder let mut encoded_solution = encoder
.encode_strategy(solution.clone()) .encode_strategy(solution.clone())
.unwrap(); .unwrap();
let (permit, signature) = get_permit(eth_chain(), router_address(), &solution); let permit = get_permit(router_address(), &solution);
encoded_solution.permit = Some(permit); encoded_solution.permit = Some(permit);
encoded_solution.signature = Some(signature.as_bytes().to_vec());
let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth()) let calldata = encode_tycho_router_call(
eth_chain().id,
encoded_solution,
&solution,
UserTransferType::TransferFromPermit2,
eth(),
Some(get_signer()),
)
.unwrap() .unwrap()
.data; .data;
@@ -2202,9 +2285,8 @@ mod tests {
let encoder = SingleSwapStrategyEncoder::new( let encoder = SingleSwapStrategyEncoder::new(
eth_chain(), eth_chain(),
swap_encoder_registry, swap_encoder_registry,
false, UserTransferType::TransferFrom,
Bytes::from_str("0xA4AD4f68d0b91CFD19687c881e50f3A00242828c").unwrap(), Bytes::from_str("0xA4AD4f68d0b91CFD19687c881e50f3A00242828c").unwrap(),
false,
) )
.unwrap(); .unwrap();
@@ -2225,7 +2307,14 @@ mod tests {
.encode_strategy(solution.clone()) .encode_strategy(solution.clone())
.unwrap(); .unwrap();
let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth()) let calldata = encode_tycho_router_call(
eth_chain().id,
encoded_solution,
&solution,
UserTransferType::TransferFrom,
eth(),
None,
)
.unwrap() .unwrap()
.data; .data;
let hex_calldata = encode(&calldata); let hex_calldata = encode(&calldata);
@@ -2253,9 +2342,8 @@ mod tests {
let encoder = SingleSwapStrategyEncoder::new( let encoder = SingleSwapStrategyEncoder::new(
eth_chain(), eth_chain(),
swap_encoder_registry, swap_encoder_registry,
false, UserTransferType::TransferFrom,
Bytes::from_str("0xA4AD4f68d0b91CFD19687c881e50f3A00242828c").unwrap(), Bytes::from_str("0xA4AD4f68d0b91CFD19687c881e50f3A00242828c").unwrap(),
false,
) )
.unwrap(); .unwrap();
@@ -2276,7 +2364,14 @@ mod tests {
.encode_strategy(solution.clone()) .encode_strategy(solution.clone())
.unwrap(); .unwrap();
let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth()) let calldata = encode_tycho_router_call(
eth_chain().id,
encoded_solution,
&solution,
UserTransferType::TransferFrom,
eth(),
None,
)
.unwrap() .unwrap()
.data; .data;
let hex_calldata = encode(&calldata); let hex_calldata = encode(&calldata);
@@ -2316,9 +2411,8 @@ mod tests {
let encoder = SingleSwapStrategyEncoder::new( let encoder = SingleSwapStrategyEncoder::new(
eth_chain(), eth_chain(),
swap_encoder_registry, swap_encoder_registry,
true, UserTransferType::TransferFromPermit2,
Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395"), Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395"),
false,
) )
.unwrap(); .unwrap();
@@ -2337,11 +2431,17 @@ mod tests {
let mut encoded_solution = encoder let mut encoded_solution = encoder
.encode_strategy(solution.clone()) .encode_strategy(solution.clone())
.unwrap(); .unwrap();
let (permit, signature) = get_permit(eth_chain(), router_address(), &solution); let permit = get_permit(router_address(), &solution);
encoded_solution.permit = Some(permit); encoded_solution.permit = Some(permit);
encoded_solution.signature = Some(signature.as_bytes().to_vec());
let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth) let calldata = encode_tycho_router_call(
eth_chain().id,
encoded_solution,
&solution,
UserTransferType::TransferFromPermit2,
eth,
Some(get_signer()),
)
.unwrap() .unwrap()
.data; .data;
let hex_calldata = encode(&calldata); let hex_calldata = encode(&calldata);
@@ -2389,9 +2489,8 @@ mod tests {
let encoder = SplitSwapStrategyEncoder::new( let encoder = SplitSwapStrategyEncoder::new(
eth_chain(), eth_chain(),
swap_encoder_registry, swap_encoder_registry,
true, UserTransferType::TransferFromPermit2,
Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395"), Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395"),
false,
) )
.unwrap(); .unwrap();
@@ -2410,11 +2509,17 @@ mod tests {
let mut encoded_solution = encoder let mut encoded_solution = encoder
.encode_strategy(solution.clone()) .encode_strategy(solution.clone())
.unwrap(); .unwrap();
let (permit, signature) = get_permit(eth_chain(), router_address(), &solution); let permit = get_permit(router_address(), &solution);
encoded_solution.permit = Some(permit); encoded_solution.permit = Some(permit);
encoded_solution.signature = Some(signature.as_bytes().to_vec());
let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth) let calldata = encode_tycho_router_call(
eth_chain().id,
encoded_solution,
&solution,
UserTransferType::TransferFromPermit2,
eth,
Some(get_signer()),
)
.unwrap() .unwrap()
.data; .data;
@@ -2481,9 +2586,8 @@ mod tests {
let encoder = SingleSwapStrategyEncoder::new( let encoder = SingleSwapStrategyEncoder::new(
eth_chain(), eth_chain(),
swap_encoder_registry, swap_encoder_registry,
true, UserTransferType::TransferFromPermit2,
Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395"), Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395"),
false,
) )
.unwrap(); .unwrap();
let solution = Solution { let solution = Solution {
@@ -2501,11 +2605,17 @@ mod tests {
let mut encoded_solution = encoder let mut encoded_solution = encoder
.encode_strategy(solution.clone()) .encode_strategy(solution.clone())
.unwrap(); .unwrap();
let (permit, signature) = get_permit(eth_chain(), router_address(), &solution); let permit = get_permit(router_address(), &solution);
encoded_solution.permit = Some(permit); encoded_solution.permit = Some(permit);
encoded_solution.signature = Some(signature.as_bytes().to_vec());
let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth) let calldata = encode_tycho_router_call(
eth_chain().id,
encoded_solution,
&solution,
UserTransferType::TransferFromPermit2,
eth,
Some(get_signer()),
)
.unwrap() .unwrap()
.data; .data;
@@ -2591,9 +2701,8 @@ mod tests {
let encoder = SingleSwapStrategyEncoder::new( let encoder = SingleSwapStrategyEncoder::new(
eth_chain(), eth_chain(),
swap_encoder_registry, swap_encoder_registry,
false, UserTransferType::TransferFrom,
router_address(), router_address(),
false,
) )
.unwrap(); .unwrap();
@@ -2614,7 +2723,14 @@ mod tests {
.encode_strategy(solution.clone()) .encode_strategy(solution.clone())
.unwrap(); .unwrap();
let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth()) let calldata = encode_tycho_router_call(
eth_chain().id,
encoded_solution,
&solution,
UserTransferType::TransferFrom,
eth(),
None,
)
.unwrap() .unwrap()
.data; .data;
@@ -2657,9 +2773,8 @@ mod tests {
let encoder = SingleSwapStrategyEncoder::new( let encoder = SingleSwapStrategyEncoder::new(
eth_chain(), eth_chain(),
swap_encoder_registry, swap_encoder_registry,
false, UserTransferType::TransferFrom,
router_address(), router_address(),
false,
) )
.unwrap(); .unwrap();
@@ -2679,7 +2794,14 @@ mod tests {
let encoded_solution = encoder let encoded_solution = encoder
.encode_strategy(solution.clone()) .encode_strategy(solution.clone())
.unwrap(); .unwrap();
let calldata = encode_tycho_router_call(encoded_solution, &solution, false, eth()) let calldata = encode_tycho_router_call(
eth_chain().id,
encoded_solution,
&solution,
UserTransferType::TransferFrom,
eth(),
None,
)
.unwrap() .unwrap()
.data; .data;

View File

@@ -8,7 +8,7 @@ use crate::encoding::{
constants::{CALLBACK_CONSTRAINED_PROTOCOLS, IN_TRANSFER_REQUIRED_PROTOCOLS}, constants::{CALLBACK_CONSTRAINED_PROTOCOLS, IN_TRANSFER_REQUIRED_PROTOCOLS},
group_swaps::SwapGroup, group_swaps::SwapGroup,
}, },
models::TransferType, models::{TransferType, UserTransferType},
}; };
/// A struct that defines how the tokens will be transferred into the given pool given the solution. /// A struct that defines how the tokens will be transferred into the given pool given the solution.
@@ -16,7 +16,7 @@ use crate::encoding::{
pub struct TransferOptimization { pub struct TransferOptimization {
native_token: Bytes, native_token: Bytes,
wrapped_token: Bytes, wrapped_token: Bytes,
token_in_already_in_router: bool, user_transfer_type: UserTransferType,
router_address: Bytes, router_address: Bytes,
} }
@@ -24,15 +24,10 @@ impl TransferOptimization {
pub fn new( pub fn new(
native_token: Bytes, native_token: Bytes,
wrapped_token: Bytes, wrapped_token: Bytes,
token_in_already_in_router: bool, user_transfer_type: UserTransferType,
router_address: Bytes, router_address: Bytes,
) -> Self { ) -> Self {
TransferOptimization { TransferOptimization { native_token, wrapped_token, user_transfer_type, router_address }
native_token,
wrapped_token,
token_in_already_in_router,
router_address,
}
} }
/// Returns the transfer type that should be used for the current transfer. /// Returns the transfer type that should be used for the current transfer.
@@ -55,7 +50,7 @@ impl TransferOptimization {
TransferType::Transfer TransferType::Transfer
} else if is_first_swap { } else if is_first_swap {
if in_transfer_required { if in_transfer_required {
if self.token_in_already_in_router { if self.user_transfer_type == UserTransferType::None {
// Transfer from router to pool. // Transfer from router to pool.
TransferType::Transfer TransferType::Transfer
} else { } else {
@@ -64,7 +59,7 @@ impl TransferOptimization {
} }
// in transfer is not necessary for these protocols. Only make a transfer from the // in transfer is not necessary for these protocols. Only make a transfer from the
// swapper to the router if the tokens are not already in the router // swapper to the router if the tokens are not already in the router
} else if !self.token_in_already_in_router { } else if self.user_transfer_type != UserTransferType::None {
// Transfer from swapper to router using. // Transfer from swapper to router using.
TransferType::TransferFrom TransferType::TransferFrom
} else { } else {
@@ -146,30 +141,30 @@ mod tests {
#[rstest] #[rstest]
// First swap tests // First swap tests
// WETH -(univ2)-> DAI we expect a transfer from the user to the protocol // WETH -(univ2)-> DAI we expect a transfer from the user to the protocol
#[case(weth(), weth(), "uniswap_v2".to_string(), false, false,false, TransferType::TransferFrom)] #[case(weth(), weth(), "uniswap_v2".to_string(), false, UserTransferType::TransferFrom,false, TransferType::TransferFrom)]
// Native token swap. No transfer is needed // Native token swap. No transfer is needed
#[case(eth(), eth(), "uniswap_v2".to_string(),false, false,false, TransferType::None)] #[case(eth(), eth(), "uniswap_v2".to_string(),false, UserTransferType::TransferFrom,false, TransferType::None)]
// ETH -(wrap)-> WETH -(univ2)-> DAI. Only a transfer from the router into the protocol is // ETH -(wrap)-> WETH -(univ2)-> DAI. Only a transfer from the router into the protocol is
// needed // needed
#[case(eth(), weth(), "uniswap_v2".to_string(),true, false,false,TransferType::Transfer)] #[case(eth(), weth(), "uniswap_v2".to_string(),true, UserTransferType::TransferFrom,false,TransferType::Transfer)]
// USDC -(univ2)-> DAI and the tokens are already in the router. Only a transfer from the router // USDC -(univ2)-> DAI and the tokens are already in the router. Only a transfer from the router
// to the protocol is needed // to the protocol is needed
#[case(usdc(), usdc(), "uniswap_v2".to_string(),false, true,false, TransferType::Transfer)] #[case(usdc(), usdc(), "uniswap_v2".to_string(),false, UserTransferType::None,false, TransferType::Transfer)]
// USDC -(curve)-> DAI and the tokens are already in the router. No transfer is needed // USDC -(curve)-> DAI and the tokens are already in the router. No transfer is needed
#[case(usdc(), usdc(), "vm:curve".to_string(),false, true, false,TransferType::None)] #[case(usdc(), usdc(), "vm:curve".to_string(),false, UserTransferType::None, false,TransferType::None)]
// other swaps tests // other swaps tests
// tokens need to be transferred into the pool // tokens need to be transferred into the pool
#[case(weth(), usdc(), "uniswap_v2".to_string(), false, false,false, TransferType::Transfer)] #[case(weth(), usdc(), "uniswap_v2".to_string(), false, UserTransferType::TransferFrom,false, TransferType::Transfer)]
// tokens are already in the pool (optimization) // tokens are already in the pool (optimization)
#[case(weth(), usdc(), "uniswap_v2".to_string(), false, false, true, TransferType::None)] #[case(weth(), usdc(), "uniswap_v2".to_string(), false, UserTransferType::TransferFrom, true, TransferType::None)]
// tokens are already in the router and don't need a transfer // tokens are already in the router and don't need a transfer
#[case(weth(), usdc(), "vm:curve".to_string(), false, false, false, TransferType::None)] #[case(weth(), usdc(), "vm:curve".to_string(), false, UserTransferType::TransferFrom, false, TransferType::None)]
fn test_get_transfers( fn test_get_transfers(
#[case] given_token: Bytes, #[case] given_token: Bytes,
#[case] swap_token_in: Bytes, #[case] swap_token_in: Bytes,
#[case] protocol: String, #[case] protocol: String,
#[case] wrap: bool, #[case] wrap: bool,
#[case] token_in_already_in_router: bool, #[case] user_transfer_type: UserTransferType,
#[case] in_between_swap_optimization: bool, #[case] in_between_swap_optimization: bool,
#[case] expected_transfer: TransferType, #[case] expected_transfer: TransferType,
) { ) {
@@ -192,7 +187,7 @@ mod tests {
swaps, swaps,
}; };
let optimization = let optimization =
TransferOptimization::new(eth(), weth(), token_in_already_in_router, router_address()); TransferOptimization::new(eth(), weth(), user_transfer_type, router_address());
let transfer = optimization.get_transfers( let transfer = optimization.get_transfers(
swap.clone(), swap.clone(),
given_token, given_token,
@@ -224,7 +219,12 @@ mod tests {
#[case] expected_receiver: Bytes, #[case] expected_receiver: Bytes,
#[case] expected_optimization: bool, #[case] expected_optimization: bool,
) { ) {
let optimization = TransferOptimization::new(eth(), weth(), false, router_address()); let optimization = TransferOptimization::new(
eth(),
weth(),
UserTransferType::TransferFrom,
router_address(),
);
let next_swap = if protocol.is_none() { let next_swap = if protocol.is_none() {
None None

View File

@@ -1,5 +1,6 @@
use std::{collections::HashSet, str::FromStr}; use std::{collections::HashSet, str::FromStr};
use alloy::signers::local::PrivateKeySigner;
use tycho_common::Bytes; use tycho_common::Bytes;
use crate::encoding::{ use crate::encoding::{
@@ -16,6 +17,7 @@ use crate::encoding::{
}, },
models::{ models::{
Chain, EncodedSolution, EncodingContext, NativeAction, Solution, Transaction, TransferType, Chain, EncodedSolution, EncodingContext, NativeAction, Solution, Transaction, TransferType,
UserTransferType,
}, },
strategy_encoder::StrategyEncoder, strategy_encoder::StrategyEncoder,
tycho_encoder::TychoEncoder, tycho_encoder::TychoEncoder,
@@ -24,37 +26,36 @@ use crate::encoding::{
/// Encodes solutions to be used by the TychoRouter. /// Encodes solutions to be used by the TychoRouter.
/// ///
/// # Fields /// # Fields
/// * `chain`: Chain to be used
/// * `single_swap_strategy`: Encoder for single swaps /// * `single_swap_strategy`: Encoder for single swaps
/// * `sequential_swap_strategy`: Encoder for sequential swaps /// * `sequential_swap_strategy`: Encoder for sequential swaps
/// * `split_swap_strategy`: Encoder for split swaps /// * `split_swap_strategy`: Encoder for split swaps
/// * `native_address`: Address of the chain's native token
/// * `wrapped_address`: Address of the chain's wrapped native token
/// * `router_address`: Address of the Tycho router contract /// * `router_address`: Address of the Tycho router contract
/// * `token_in_already_in_router`: Indicates if the token in is already in the router at swap time /// * `user_transfer_type`: Type of user transfer
/// * `permit2`: Optional Permit2 instance for permit transfers
/// * `signer`: Optional signer (used only for permit2 and full calldata encoding)
#[derive(Clone)] #[derive(Clone)]
pub struct TychoRouterEncoder { pub struct TychoRouterEncoder {
chain: Chain,
single_swap_strategy: SingleSwapStrategyEncoder, single_swap_strategy: SingleSwapStrategyEncoder,
sequential_swap_strategy: SequentialSwapStrategyEncoder, sequential_swap_strategy: SequentialSwapStrategyEncoder,
split_swap_strategy: SplitSwapStrategyEncoder, split_swap_strategy: SplitSwapStrategyEncoder,
native_address: Bytes,
wrapped_address: Bytes,
router_address: Bytes, router_address: Bytes,
token_in_already_in_router: bool, user_transfer_type: UserTransferType,
permit2: Option<Permit2>, permit2: Option<Permit2>,
signer: Option<PrivateKeySigner>,
} }
impl TychoRouterEncoder { impl TychoRouterEncoder {
pub fn new( pub fn new(
chain: Chain, chain: Chain,
swap_encoder_registry: SwapEncoderRegistry, swap_encoder_registry: SwapEncoderRegistry,
swapper_pk: Option<String>,
router_address: Bytes, router_address: Bytes,
token_in_already_in_router: bool, user_transfer_type: UserTransferType,
signer: Option<PrivateKeySigner>,
) -> Result<Self, EncodingError> { ) -> Result<Self, EncodingError> {
let native_address = chain.native_token()?; let permit2 = if user_transfer_type == UserTransferType::TransferFromPermit2 {
let wrapped_address = chain.wrapped_token()?; Some(Permit2::new()?)
let permit2 = if let Some(swapper_pk) = swapper_pk.clone() {
Some(Permit2::new(swapper_pk, chain.clone())?)
} else { } else {
None None
}; };
@@ -62,29 +63,26 @@ impl TychoRouterEncoder {
single_swap_strategy: SingleSwapStrategyEncoder::new( single_swap_strategy: SingleSwapStrategyEncoder::new(
chain.clone(), chain.clone(),
swap_encoder_registry.clone(), swap_encoder_registry.clone(),
permit2.is_some(), user_transfer_type.clone(),
router_address.clone(), router_address.clone(),
token_in_already_in_router,
)?, )?,
sequential_swap_strategy: SequentialSwapStrategyEncoder::new( sequential_swap_strategy: SequentialSwapStrategyEncoder::new(
chain.clone(), chain.clone(),
swap_encoder_registry.clone(), swap_encoder_registry.clone(),
permit2.is_some(), user_transfer_type.clone(),
router_address.clone(), router_address.clone(),
token_in_already_in_router,
)?, )?,
split_swap_strategy: SplitSwapStrategyEncoder::new( split_swap_strategy: SplitSwapStrategyEncoder::new(
chain, chain.clone(),
swap_encoder_registry, swap_encoder_registry,
permit2.is_some(), user_transfer_type.clone(),
router_address.clone(), router_address.clone(),
token_in_already_in_router,
)?, )?,
native_address,
wrapped_address,
router_address, router_address,
token_in_already_in_router,
permit2, permit2,
signer,
chain,
user_transfer_type,
}) })
} }
@@ -118,14 +116,13 @@ impl TychoRouterEncoder {
}; };
if let Some(permit2) = self.permit2.clone() { if let Some(permit2) = self.permit2.clone() {
let (permit, signature) = permit2.get_permit( let permit = permit2.get_permit(
&self.router_address, &self.router_address,
&solution.sender, &solution.sender,
&solution.given_token, &solution.given_token,
&solution.given_amount, &solution.given_amount,
)?; )?;
encoded_solution.permit = Some(permit); encoded_solution.permit = Some(permit);
encoded_solution.signature = Some(signature.as_bytes().to_vec());
} }
Ok(encoded_solution) Ok(encoded_solution)
} }
@@ -153,10 +150,12 @@ impl TychoEncoder for TychoRouterEncoder {
let encoded_solution = self.encode_solution(solution)?; let encoded_solution = self.encode_solution(solution)?;
let transaction = encode_tycho_router_call( let transaction = encode_tycho_router_call(
self.chain.id,
encoded_solution, encoded_solution,
solution, solution,
self.token_in_already_in_router, self.user_transfer_type.clone(),
self.native_address.clone(), self.chain.native_token()?.clone(),
self.signer.clone(),
)?; )?;
transactions.push(transaction); transactions.push(transaction);
@@ -184,15 +183,17 @@ impl TychoEncoder for TychoRouterEncoder {
if solution.swaps.is_empty() { if solution.swaps.is_empty() {
return Err(EncodingError::FatalError("No swaps found in solution".to_string())); return Err(EncodingError::FatalError("No swaps found in solution".to_string()));
} }
let native_address = self.chain.native_token()?;
let wrapped_address = self.chain.wrapped_token()?;
if let Some(native_action) = solution.clone().native_action { if let Some(native_action) = solution.clone().native_action {
if native_action == NativeAction::Wrap { if native_action == NativeAction::Wrap {
if solution.given_token != self.native_address { if solution.given_token != native_address {
return Err(EncodingError::FatalError( return Err(EncodingError::FatalError(
"Native token must be the input token in order to wrap".to_string(), "Native token must be the input token in order to wrap".to_string(),
)); ));
} }
if let Some(first_swap) = solution.swaps.first() { if let Some(first_swap) = solution.swaps.first() {
if first_swap.token_in != self.wrapped_address { if first_swap.token_in != wrapped_address {
return Err(EncodingError::FatalError( return Err(EncodingError::FatalError(
"Wrapped token must be the first swap's input in order to wrap" "Wrapped token must be the first swap's input in order to wrap"
.to_string(), .to_string(),
@@ -200,13 +201,13 @@ impl TychoEncoder for TychoRouterEncoder {
} }
} }
} else if native_action == NativeAction::Unwrap { } else if native_action == NativeAction::Unwrap {
if solution.checked_token != self.native_address { if solution.checked_token != native_address {
return Err(EncodingError::FatalError( return Err(EncodingError::FatalError(
"Native token must be the output token in order to unwrap".to_string(), "Native token must be the output token in order to unwrap".to_string(),
)); ));
} }
if let Some(last_swap) = solution.swaps.last() { if let Some(last_swap) = solution.swaps.last() {
if last_swap.token_out != self.wrapped_address { if last_swap.token_out != wrapped_address {
return Err(EncodingError::FatalError( return Err(EncodingError::FatalError(
"Wrapped token must be the last swap's output in order to unwrap" "Wrapped token must be the last swap's output in order to unwrap"
.to_string(), .to_string(),
@@ -337,7 +338,6 @@ impl TychoExecutorEncoder {
swaps: grouped_protocol_data, swaps: grouped_protocol_data,
interacting_with: executor_address, interacting_with: executor_address,
permit: None, permit: None,
signature: None,
selector: "".to_string(), selector: "".to_string(),
n_tokens: 0, n_tokens: 0,
}) })
@@ -474,13 +474,14 @@ mod tests {
TychoRouterEncoder::new( TychoRouterEncoder::new(
TychoCommonChain::Ethereum.into(), TychoCommonChain::Ethereum.into(),
get_swap_encoder_registry(), get_swap_encoder_registry(),
None,
Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(), Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(),
false, UserTransferType::TransferFrom,
None,
) )
.unwrap() .unwrap()
} }
#[test] #[test]
#[allow(deprecated)]
fn test_encode_router_calldata_single_swap() { fn test_encode_router_calldata_single_swap() {
let encoder = get_tycho_router_encoder(); let encoder = get_tycho_router_encoder();
let eth_amount_in = BigUint::from(1000u32); let eth_amount_in = BigUint::from(1000u32);
@@ -520,6 +521,7 @@ mod tests {
} }
#[test] #[test]
#[allow(deprecated)]
fn test_encode_router_calldata_single_swap_group() { fn test_encode_router_calldata_single_swap_group() {
let encoder = get_tycho_router_encoder(); let encoder = get_tycho_router_encoder();
let solution = Solution { let solution = Solution {
@@ -543,6 +545,7 @@ mod tests {
} }
#[test] #[test]
#[allow(deprecated)]
fn test_encode_router_calldata_sequential_swap() { fn test_encode_router_calldata_sequential_swap() {
let encoder = get_tycho_router_encoder(); let encoder = get_tycho_router_encoder();
let eth_amount_in = BigUint::from(1000u32); let eth_amount_in = BigUint::from(1000u32);

View File

@@ -1,3 +1,4 @@
use clap::ValueEnum;
use hex; use hex;
use num_bigint::BigUint; use num_bigint::BigUint;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@@ -8,6 +9,31 @@ use tycho_common::{
use crate::encoding::{errors::EncodingError, serde_primitives::biguint_string}; use crate::encoding::{errors::EncodingError, serde_primitives::biguint_string};
/// Specifies the method for transferring user funds into Tycho execution.
///
/// Options:
///
/// - `TransferFromPermit2`: Use Permit2 for token transfer.
/// - You must manually approve the Permit2 contract and sign the permit object externally
/// (outside `tycho-execution`).
///
/// - `TransferFrom`: Use standard ERC-20 approval and `transferFrom`.
/// - You must approve the Tycho Router contract to spend your tokens via standard `approve()`
/// calls.
///
/// - `None`: No transfer will be performed.
/// - Assumes the tokens are already present in the Tycho Router.
/// - **Warning**: This is an advanced mode. Ensure your logic guarantees that the tokens are
/// already in the router at the time of execution.
/// - The Tycho router is **not** designed to safely hold tokens. If tokens are not transferred
/// and used in the **same transaction**, they will be permanently lost.
#[derive(Clone, Debug, PartialEq, ValueEnum)]
pub enum UserTransferType {
TransferFromPermit2,
TransferFrom,
None,
}
/// Represents a solution containing details describing an order, and instructions for filling /// Represents a solution containing details describing an order, and instructions for filling
/// the order. /// the order.
#[derive(Clone, Default, Debug, Deserialize, Serialize)] #[derive(Clone, Default, Debug, Deserialize, Serialize)]
@@ -95,7 +121,6 @@ pub struct Transaction {
/// * `selector`: The selector of the function to be called. /// * `selector`: The selector of the function to be called.
/// * `n_tokens`: Number of tokens in the swap. /// * `n_tokens`: Number of tokens in the swap.
/// * `permit`: Optional permit for the swap (if permit2 is enabled). /// * `permit`: Optional permit for the swap (if permit2 is enabled).
/// * `signature`: Optional signature for the swap (if permit2 is enabled).
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct EncodedSolution { pub struct EncodedSolution {
pub swaps: Vec<u8>, pub swaps: Vec<u8>,
@@ -103,7 +128,6 @@ pub struct EncodedSolution {
pub selector: String, pub selector: String,
pub n_tokens: usize, pub n_tokens: usize,
pub permit: Option<PermitSingle>, pub permit: Option<PermitSingle>,
pub signature: Option<Vec<u8>>,
} }
/// Represents a single permit for permit2. /// Represents a single permit for permit2.

View File

@@ -61,6 +61,7 @@ pub trait TychoEncoder {
/// ///
/// # Returns /// # Returns
/// A vector of fully constructed [`Transaction`]s that can be submitted to a node or bundler. /// A vector of fully constructed [`Transaction`]s that can be submitted to a node or bundler.
#[deprecated(note = "Please use `encode_solutions` instead")]
fn encode_full_calldata( fn encode_full_calldata(
&self, &self,
solutions: Vec<Solution>, solutions: Vec<Solution>,