Merge pull request #78 from propeller-heads/encoding/tnl/ENG-4259-native-eth-integration
fix: Native ETH input/output integration tests/fixes
This commit is contained in:
@@ -124,7 +124,13 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
|
|||||||
revert TychoRouter__NegativeSlippage(amountOut, minAmountOut);
|
revert TychoRouter__NegativeSlippage(amountOut, minAmountOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint256 leftoverAmountIn = IERC20(tokenIn).balanceOf(address(this));
|
uint256 leftoverAmountIn;
|
||||||
|
if (tokenIn == address(0)) {
|
||||||
|
leftoverAmountIn = address(this).balance;
|
||||||
|
} else {
|
||||||
|
leftoverAmountIn = IERC20(tokenIn).balanceOf(address(this));
|
||||||
|
}
|
||||||
|
|
||||||
if (leftoverAmountIn > 0) {
|
if (leftoverAmountIn > 0) {
|
||||||
revert TychoRouter__AmountInNotFullySpent(leftoverAmountIn);
|
revert TychoRouter__AmountInNotFullySpent(leftoverAmountIn);
|
||||||
}
|
}
|
||||||
@@ -209,7 +215,13 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
|
|||||||
revert TychoRouter__NegativeSlippage(amountOut, minAmountOut);
|
revert TychoRouter__NegativeSlippage(amountOut, minAmountOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint256 leftoverAmountIn = IERC20(tokenIn).balanceOf(address(this));
|
uint256 leftoverAmountIn;
|
||||||
|
if (tokenIn == address(0)) {
|
||||||
|
leftoverAmountIn = address(this).balance;
|
||||||
|
} else {
|
||||||
|
leftoverAmountIn = IERC20(tokenIn).balanceOf(address(this));
|
||||||
|
}
|
||||||
|
|
||||||
if (leftoverAmountIn > 0) {
|
if (leftoverAmountIn > 0) {
|
||||||
revert TychoRouter__AmountInNotFullySpent(leftoverAmountIn);
|
revert TychoRouter__AmountInNotFullySpent(leftoverAmountIn);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,8 +71,8 @@ contract UniswapV4Executor is IExecutor, V4Router {
|
|||||||
hookData: bytes("")
|
hookData: bytes("")
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
params[1] = abi.encode(key.currency0, amountIn);
|
params[1] = abi.encode(tokenIn, amountIn); // currency to settle
|
||||||
params[2] = abi.encode(key.currency1, uint256(0));
|
params[2] = abi.encode(tokenOut, uint256(0)); // currency to take
|
||||||
swapData = abi.encode(actions, params);
|
swapData = abi.encode(actions, params);
|
||||||
} else {
|
} else {
|
||||||
PathKey[] memory path = new PathKey[](pools.length);
|
PathKey[] memory path = new PathKey[](pools.length);
|
||||||
|
|||||||
@@ -735,8 +735,7 @@ contract TychoRouterTest is TychoRouterTestSetup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function testUSV4Integration() public {
|
function testUSV4Integration() public {
|
||||||
// Test created with calldata from our router encoder, replacing the executor
|
// Test created with calldata from our router encoder.
|
||||||
// address with the USV4 executor address.
|
|
||||||
|
|
||||||
// Performs a sequential swap from USDC to PEPE though ETH using two
|
// Performs a sequential swap from USDC to PEPE though ETH using two
|
||||||
// consecutive USV4 pools
|
// consecutive USV4 pools
|
||||||
@@ -750,8 +749,7 @@ contract TychoRouterTest is TychoRouterTestSetup {
|
|||||||
vm.startPrank(ALICE);
|
vm.startPrank(ALICE);
|
||||||
IERC20(USDC_ADDR).approve(address(permit2Address), type(uint256).max);
|
IERC20(USDC_ADDR).approve(address(permit2Address), type(uint256).max);
|
||||||
// Encoded solution generated using `test_split_encoding_strategy_usv4`
|
// Encoded solution generated using `test_split_encoding_strategy_usv4`
|
||||||
// but manually replacing the executor address
|
// and ensuring that the encoded executor address is the one in this test
|
||||||
// `5c2f5a71f67c01775180adc06909288b4c329308` with the one in this test
|
|
||||||
// `f62849f9a0b5bf2913b396098f7c7019b51a820a`
|
// `f62849f9a0b5bf2913b396098f7c7019b51a820a`
|
||||||
(bool success,) = tychoRouterAddr.call(
|
(bool success,) = tychoRouterAddr.call(
|
||||||
hex"d499aa88000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000067ddee9e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067b668a6000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041bdf91011918dcb5f59ab3588212a035c770a2839fe2c19060491370fa89685b8469def9e83c7b9cf8f0ef5088a3179556a6ba1096cefbe83c09a1182981c93e41c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009400920001000000f62849f9a0b5bf2913b396098f7c7019b51a820abd0625aba0b86991c6218b36c1d19d4a2e9eb0ce3606eb486982508145454ce325ddbe47a25d4ec3d231193300f62849f9a0b5bf2913b396098f7c7019b51a820a91dd73460000000000000000000000000000000000000000000bb800003c6982508145454ce325ddbe47a25d4ec3d23119330061a80001f4000000000000000000000000"
|
hex"d499aa88000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000067ddee9e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067b668a6000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041bdf91011918dcb5f59ab3588212a035c770a2839fe2c19060491370fa89685b8469def9e83c7b9cf8f0ef5088a3179556a6ba1096cefbe83c09a1182981c93e41c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009400920001000000f62849f9a0b5bf2913b396098f7c7019b51a820abd0625aba0b86991c6218b36c1d19d4a2e9eb0ce3606eb486982508145454ce325ddbe47a25d4ec3d231193300f62849f9a0b5bf2913b396098f7c7019b51a820a91dd73460000000000000000000000000000000000000000000bb800003c6982508145454ce325ddbe47a25d4ec3d23119330061a80001f4000000000000000000000000"
|
||||||
@@ -765,6 +763,61 @@ contract TychoRouterTest is TychoRouterTestSetup {
|
|||||||
assertEq(balancerAfter - balancerBefore, 97191013220606467325121599);
|
assertEq(balancerAfter - balancerBefore, 97191013220606467325121599);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function testUSV4IntegrationInputETH() public {
|
||||||
|
// Test created with calldata from our router encoder.
|
||||||
|
|
||||||
|
// Performs a single swap from ETH to PEPE without wrapping or unwrapping
|
||||||
|
//
|
||||||
|
// ETH ───(USV4)──> PEPE
|
||||||
|
//
|
||||||
|
deal(ALICE, 1 ether);
|
||||||
|
uint256 balancerBefore = IERC20(PEPE_ADDR).balanceOf(ALICE);
|
||||||
|
|
||||||
|
// Encoded solution generated using `test_split_encoding_strategy_usv4_eth_in`
|
||||||
|
// and ensuring that the encoded executor address is the one in this test
|
||||||
|
// `f62849f9a0b5bf2913b396098f7c7019b51a820a`
|
||||||
|
(bool success,) = tychoRouterAddr.call{value: 1 ether}(
|
||||||
|
hex"d499aa880000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000067def8e900000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067b772f100000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000004192bf6f59a6e114588b4b5fb00f3acae3eb2dd18b673924b9cf27d1414be469b70113e4ceef228e11c91d178fea26673d9edcd013dee23fa3c45abdfcb573c9371c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a00780001000000f62849f9a0b5bf2913b396098f7c7019b51a820abd0625ab00000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d231193301f62849f9a0b5bf2913b396098f7c7019b51a820a91dd73466982508145454ce325ddbe47a25d4ec3d23119330061a80001f4000000000000"
|
||||||
|
);
|
||||||
|
|
||||||
|
vm.stopPrank();
|
||||||
|
|
||||||
|
uint256 balancerAfter = IERC20(PEPE_ADDR).balanceOf(ALICE);
|
||||||
|
|
||||||
|
assertTrue(success, "Call Failed");
|
||||||
|
assertEq(balancerAfter - balancerBefore, 242373460199848577067005852);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testUSV4IntegrationOutputETH() public {
|
||||||
|
// Test created with calldata from our router encoder.
|
||||||
|
|
||||||
|
// Performs a single swap from USDC to ETH without wrapping or unwrapping
|
||||||
|
//
|
||||||
|
// USDC ───(USV4)──> ETH
|
||||||
|
//
|
||||||
|
deal(USDC_ADDR, ALICE, 3000_000000);
|
||||||
|
uint256 balancerBefore = ALICE.balance;
|
||||||
|
|
||||||
|
// Approve permit2
|
||||||
|
vm.startPrank(ALICE);
|
||||||
|
IERC20(USDC_ADDR).approve(address(permit2Address), type(uint256).max);
|
||||||
|
|
||||||
|
// Encoded solution generated using `test_split_encoding_strategy_usv4_eth_out`
|
||||||
|
// and ensuring that the encoded executor address is the one in this test
|
||||||
|
// `f62849f9a0b5bf2913b396098f7c7019b51a820a`
|
||||||
|
(bool success,) = tychoRouterAddr.call(
|
||||||
|
hex"d499aa8800000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000b2d05e000000000000000000000000000000000000000000000000000000000067df206000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067b79a68000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041d603720f916c45405d4655476fc8f5d5e93e561d1bc1bbd944f865ac2b53638e28fa06fde0c1097d688029c85940a53ba54902b42d17378159ae4affb8b958b01b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a00780001000000f62849f9a0b5bf2913b396098f7c7019b51a820abd0625aba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000f62849f9a0b5bf2913b396098f7c7019b51a820a91dd73460000000000000000000000000000000000000000000bb800003c000000000000"
|
||||||
|
);
|
||||||
|
|
||||||
|
vm.stopPrank();
|
||||||
|
|
||||||
|
uint256 balancerAfter = ALICE.balance;
|
||||||
|
|
||||||
|
assertTrue(success, "Call Failed");
|
||||||
|
console.logUint(balancerAfter - balancerBefore);
|
||||||
|
assertEq(balancerAfter - balancerBefore, 1117254495486192350);
|
||||||
|
}
|
||||||
|
|
||||||
function testSingleSwapWithWrapIntegration() public {
|
function testSingleSwapWithWrapIntegration() public {
|
||||||
// Test created with calldata from our router encoder, replacing the executor
|
// Test created with calldata from our router encoder, replacing the executor
|
||||||
// address with the USV2 executor address.
|
// address with the USV2 executor address.
|
||||||
|
|||||||
@@ -1034,7 +1034,6 @@ mod tests {
|
|||||||
));
|
));
|
||||||
let hex_calldata = encode(&calldata);
|
let hex_calldata = encode(&calldata);
|
||||||
|
|
||||||
println!("{}", hex_calldata);
|
|
||||||
assert_eq!(hex_calldata[..520], expected_input);
|
assert_eq!(hex_calldata[..520], expected_input);
|
||||||
assert_eq!(hex_calldata[1288..], expected_swaps);
|
assert_eq!(hex_calldata[1288..], expected_swaps);
|
||||||
}
|
}
|
||||||
@@ -1118,4 +1117,129 @@ mod tests {
|
|||||||
assert_eq!(hex_calldata, expected_input);
|
assert_eq!(hex_calldata, expected_input);
|
||||||
println!("{}", hex_calldata);
|
println!("{}", hex_calldata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_split_encoding_strategy_usv4_eth_in() {
|
||||||
|
// Performs a single swap from ETH to PEPE using a USV4 pool
|
||||||
|
// Note: This test does not assert anything. It is only used to obtain integration test
|
||||||
|
// data for our router solidity test.
|
||||||
|
//
|
||||||
|
// ETH ───(USV4)──> PEPE
|
||||||
|
//
|
||||||
|
// Set up a mock private key for signing (Alice's pk in our router tests)
|
||||||
|
let private_key =
|
||||||
|
"0x123456789abcdef123456789abcdef123456789abcdef123456789abcdef1234".to_string();
|
||||||
|
|
||||||
|
let eth = eth();
|
||||||
|
let pepe = Bytes::from_str("0x6982508145454Ce325dDbE47a25d4ec3d2311933").unwrap();
|
||||||
|
|
||||||
|
let pool_fee_eth_pepe = Bytes::from(BigInt::from(25000).to_signed_bytes_be());
|
||||||
|
let tick_spacing_eth_pepe = Bytes::from(BigInt::from(500).to_signed_bytes_be());
|
||||||
|
let mut static_attributes_eth_pepe: HashMap<String, Bytes> = HashMap::new();
|
||||||
|
static_attributes_eth_pepe.insert("fee".into(), pool_fee_eth_pepe);
|
||||||
|
static_attributes_eth_pepe.insert("tick_spacing".into(), tick_spacing_eth_pepe);
|
||||||
|
|
||||||
|
let swap_eth_pepe = Swap {
|
||||||
|
component: ProtocolComponent {
|
||||||
|
id: "0xecd73ecbf77219f21f129c8836d5d686bbc27d264742ddad620500e3e548e2c9"
|
||||||
|
.to_string(),
|
||||||
|
protocol_system: "uniswap_v4".to_string(),
|
||||||
|
static_attributes: static_attributes_eth_pepe,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
token_in: eth.clone(),
|
||||||
|
token_out: pepe.clone(),
|
||||||
|
split: 0f64,
|
||||||
|
};
|
||||||
|
let swap_encoder_registry = get_swap_encoder_registry();
|
||||||
|
let encoder =
|
||||||
|
SplitSwapStrategyEncoder::new(eth_chain(), swap_encoder_registry, Some(private_key))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let solution = Solution {
|
||||||
|
exact_out: false,
|
||||||
|
given_token: eth,
|
||||||
|
given_amount: BigUint::from_str("1_000000000000000000").unwrap(),
|
||||||
|
checked_token: pepe,
|
||||||
|
expected_amount: Some(BigUint::from_str("300_000_000000000000000000").unwrap()),
|
||||||
|
checked_amount: None,
|
||||||
|
slippage: None,
|
||||||
|
sender: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||||
|
receiver: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||||
|
router_address: Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(),
|
||||||
|
swaps: vec![swap_eth_pepe],
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let (calldata, _, _) = encoder
|
||||||
|
.encode_strategy(solution)
|
||||||
|
.unwrap();
|
||||||
|
let hex_calldata = encode(&calldata);
|
||||||
|
|
||||||
|
println!("{}", hex_calldata);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn test_split_encoding_strategy_usv4_eth_out() {
|
||||||
|
// Performs a single swap from USDC to ETH using a USV4 pool
|
||||||
|
// Note: This test does not assert anything. It is only used to obtain integration test
|
||||||
|
// data for our router solidity test.
|
||||||
|
//
|
||||||
|
// USDC ───(USV4)──> ETH
|
||||||
|
//
|
||||||
|
// Set up a mock private key for signing (Alice's pk in our router tests)
|
||||||
|
let private_key =
|
||||||
|
"0x123456789abcdef123456789abcdef123456789abcdef123456789abcdef1234".to_string();
|
||||||
|
|
||||||
|
let eth = eth();
|
||||||
|
let usdc = Bytes::from_str("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48").unwrap();
|
||||||
|
|
||||||
|
// Fee and tick spacing information for this test is obtained by querying the
|
||||||
|
// USV4 Position Manager contract: 0xbd216513d74c8cf14cf4747e6aaa6420ff64ee9e
|
||||||
|
// Using the poolKeys function with the first 25 bytes of the pool id
|
||||||
|
let pool_fee_usdc_eth = Bytes::from(BigInt::from(3000).to_signed_bytes_be());
|
||||||
|
let tick_spacing_usdc_eth = Bytes::from(BigInt::from(60).to_signed_bytes_be());
|
||||||
|
let mut static_attributes_usdc_eth: HashMap<String, Bytes> = HashMap::new();
|
||||||
|
static_attributes_usdc_eth.insert("fee".into(), pool_fee_usdc_eth);
|
||||||
|
static_attributes_usdc_eth.insert("tick_spacing".into(), tick_spacing_usdc_eth);
|
||||||
|
|
||||||
|
let swap_usdc_eth = Swap {
|
||||||
|
component: ProtocolComponent {
|
||||||
|
id: "0xdce6394339af00981949f5f3baf27e3610c76326a700af57e4b3e3ae4977f78d"
|
||||||
|
.to_string(),
|
||||||
|
protocol_system: "uniswap_v4".to_string(),
|
||||||
|
static_attributes: static_attributes_usdc_eth,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
token_in: usdc.clone(),
|
||||||
|
token_out: eth.clone(),
|
||||||
|
split: 0f64,
|
||||||
|
};
|
||||||
|
|
||||||
|
let swap_encoder_registry = get_swap_encoder_registry();
|
||||||
|
let encoder =
|
||||||
|
SplitSwapStrategyEncoder::new(eth_chain(), swap_encoder_registry, Some(private_key))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let solution = Solution {
|
||||||
|
exact_out: false,
|
||||||
|
given_token: usdc,
|
||||||
|
given_amount: BigUint::from_str("3000_000000").unwrap(),
|
||||||
|
checked_token: eth,
|
||||||
|
expected_amount: Some(BigUint::from_str("1_000000000000000000").unwrap()),
|
||||||
|
checked_amount: None,
|
||||||
|
slippage: None,
|
||||||
|
sender: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||||
|
receiver: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||||
|
router_address: Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(),
|
||||||
|
swaps: vec![swap_usdc_eth],
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let (calldata, _, _) = encoder
|
||||||
|
.encode_strategy(solution)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let hex_calldata = encode(&calldata);
|
||||||
|
println!("{}", hex_calldata);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user