Merge branch 'main' into router/hr/ENG-4280-gas-test

This commit is contained in:
Harsh Vardhan Roy
2025-03-01 00:11:34 +05:30
committed by GitHub
13 changed files with 60 additions and 124 deletions

View File

@@ -1,3 +1,15 @@
## [0.56.0](https://github.com/propeller-heads/tycho-execution/compare/0.55.0...0.56.0) (2025-02-28)
### Features
* update base executor addresses ([bc47c12](https://github.com/propeller-heads/tycho-execution/commit/bc47c12a1a8cae0b9464b4899b52369e5036c9f7))
### Bug Fixes
* make USV2 factory configurable in Executor ([33973a6](https://github.com/propeller-heads/tycho-execution/commit/33973a65b8486c2c78e68c6a35374bd35775a7e5))
## [0.55.0](https://github.com/propeller-heads/tycho-execution/compare/0.54.0...0.55.0) (2025-02-27)

2
Cargo.lock generated
View File

@@ -4340,7 +4340,7 @@ dependencies = [
[[package]]
name = "tycho-execution"
version = "0.55.0"
version = "0.56.0"
dependencies = [
"alloy",
"alloy-primitives",

View File

@@ -1,6 +1,6 @@
[package]
name = "tycho-execution"
version = "0.55.0"
version = "0.56.0"
edition = "2021"
[[bin]]

109
README.md
View File

@@ -6,110 +6,9 @@ Tycho Execution makes it easy to trade on different DEXs by handling the complex
custom code for each DEX, you get a simple, ready-to-use tool that generates the necessary data to execute trades. It's
designed to be safe, straightforward, and quick to set up, so anyone can start trading without extra effort.
## Quickstart
For complete documentation, see Tycho docs [here](https://docs.propellerheads.xyz/tycho/for-solvers/execution).
To get started, have a look at our [Quickstart example](examples/quickstart/README.md).
## Examples
## Bin Usage Guide
### Installation
First, build and install the binary:
```bash
# Build the project
cargo build --release
# Install the binary to your system
cargo install --path .
```
After installation, the `tycho-encode` command will be available to use from any directory in your terminal.
### Commands
The command lets you choose the encoding strategy to be used. The available strategies are:
#### Tycho Router
`tycho-router`: Encodes a transaction using the Tycho Router encoding strategy.
Example:
```bash
echo '<solution_payload>' | tycho-encode tycho-router
```
#### Tycho Router With Permit2
`tycho-router-with-permit2`: Encodes a transaction using the Tycho Router encoding strategy. Requires a private key for
signing
Permit2.
Example:
```bash
echo '<solution_payload>' | tycho-encode tycho-router --swapper-pk 0x123456789abcdef123456789abcdef123456789abcdef123456789abcdef1234
```
#### Direct execution
`direct-execution`: Encodes a transaction using the direct execution encoding strategy. Does not require a private key.
Example:
```bash
echo '<solution_payload>' | tycho-encode direct-execution
```
### Encoding Transactions
The commands accept the following options:
- `--config_path`: Path to the executor addresses configuration file (defaults
to `src/encoding/config/executor_addresses.json`)
- `--swapper-pk`: Private key for signing approvals (required when direct_execution is false)
#### Example
Here's a complete example that encodes a swap from WETH to DAI using Uniswap V2 and the Tycho Router strategy:
```bash
echo '{"sender":"0x1234567890123456789012345678901234567890","receiver":"0x1234567890123456789012345678901234567890","given_token":"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2","given_amount":"1000000000000000000","checked_token":"0x6B175474E89094C44Da98b954EedeAC495271d0F","exact_out":false,"slippage":0.01,"expected_amount":"1000000000000000000","checked_amount":"990000000000000000","router_address":"0xaa820C29648D5EA543d712cC928377Bd7206a0E7","swaps":[{"component":{"id":"0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640","protocol_system":"uniswap_v2","protocol_type_name":"UniswapV2Pool","chain":"ethereum","tokens":["0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"],"contract_ids":["0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D"],"static_attributes":{"factory":"0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f"},"change":"Update","creation_tx":"0x0000000000000000000000000000000000000000000000000000000000000000","created_at":"2024-02-28T12:00:00"},"token_in":"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2","token_out":"0x6B175474E89094C44Da98b954EedeAC495271d0F","split":0.0}],"direct_execution":true}' | tycho-encode tycho-router-permit2 --swapper-pk 0x123456789abcdef123456789abcdef123456789abcdef123456789abcdef1234
```
#### JSON Payload Structure: Solution struct
The `Solution` struct is composed of the following fields:
- `sender`: The address initiating the transaction
- `receiver`: The address receiving the output tokens
- `given_token`: The address of the input token (e.g., WETH)
- `given_amount`: The amount of input tokens (in wei)
- `checked_token`: The address of the output token (e.g., DAI)
- `exact_out`: Boolean indicating if this is an exact output swap
- `slippage`: The maximum allowed slippage (e.g., 0.01 for 1%)
- `expected_amount`: The expected output amount
- `checked_amount`: The minimum acceptable output amount (accounting for slippage)
- `swaps`: Array of swap steps, each containing:
- `component`: Details about the DEX/protocol being used
- `token_in`: Input token address for this step
- `token_out`: Output token address for this step
- `split`: Proportion of tokens to route through this step (1.0 = 100%)
- `router_address`: The address of the protocol's router contract
- `direct_execution`: Boolean indicating if the transaction should be executed directly
## Contract Analysis
We use [Slither](https://github.com/crytic/slither) to detect any potential vulnerabilities in our contracts.
To run locally, simply install Slither in your conda env and run it inside the foundry directory.
```bash
conda create --name tycho-execution python=3.10
conda activate tycho-execution
pip install slither-analyzer
cd foundry
slither .
```
To get started on encoding, have a look at our [Encoding example](examples/encoding-example/README.md).
For a complete example please refer to the [Tycho Quickstart guide](https://docs.propellerheads.xyz/tycho).

View File

@@ -12,7 +12,10 @@
"vm:balancer_v2": "0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"
},
"base": {
"uniswap_v2": "0x2DaE954eCF457276F90B68Cee68981C0aA07f2ef"
"uniswap_v2": "0xa2D6c55676D0d2A1D090e3157aCC9a41bB53BE3B",
"uniswap_v3": "0x374fFd7224422dF5dE83B43C7Fa8379F9CAA826a",
"uniswap_v4": "0xf1531642018C9Ab6a1B07666755d975eae16a01b",
"vm:balancer_v2": "0x6920209CaAF45872006eC507f2f18595af030418"
},
"tenderly_base": {
"uniswap_v3": "0x7c7E06d7317e620a185078e236879D2a87fC8d22"

View File

@@ -1,6 +1,6 @@
# QuickStart
# Encoding example
This quickstart guide enables you to:
This guide enables you to:
1. Create a Solution object
2. Encode the solution to interact with the Ethereum blockchain
@@ -8,5 +8,5 @@ This quickstart guide enables you to:
## How to run
```bash
cargo run --release --example quickstart
cargo run --release --example encoding-example
```

View File

@@ -3,12 +3,21 @@ const {ethers} = require("hardhat");
const hre = require("hardhat");
// Comment out the executors you don't want to deploy
const executors_to_deploy = [
{exchange: "UniswapV2Executor", args: []},
const executors_to_deploy = {
"ethereum":[
{exchange: "UniswapV2Executor", args: ["0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f"]},
{exchange: "UniswapV3Executor", args: ["0x1F98431c8aD98523631AE4a59f267346ea31F984"]},
{exchange: "UniswapV4Executor", args: ["0x000000000004444c5dc75cB358380D2e3dE08A90"]},
{exchange: "BalancerV2Executor", args: []},
]
],
"base":[
{exchange: "UniswapV2Executor", args: ["0x8909Dc15e40173Ff4699343b6eB8132c65e18eC6"]},
{exchange: "UniswapV3Executor", args: ["0x33128a8fC17869897dcE68Ed026d694621f6FDfD"]},
{exchange: "UniswapV4Executor", args: ["0x498581ff718922c3f8e6a244956af099b2652b2b"]},
{exchange: "BalancerV2Executor", args: []},
],
}
async function main() {
const network = hre.network.name;
@@ -18,7 +27,7 @@ async function main() {
console.log(`Deploying with account: ${deployer.address}`);
console.log(`Account balance: ${ethers.utils.formatEther(await deployer.getBalance())} ETH`);
for (const executor of executors_to_deploy) {
for (const executor of executors_to_deploy[network]) {
const {exchange, args} = executor;
const Executor = await ethers.getContractFactory(exchange);
const deployedExecutor = await Executor.deploy(...args);

View File

@@ -7,6 +7,7 @@ import "@uniswap-v2/contracts/interfaces/IUniswapV2Pair.sol";
error UniswapV2Executor__InvalidDataLength();
error UniswapV2Executor__InvalidTarget();
error UniswapV2Executor__InvalidFactory();
contract UniswapV2Executor is IExecutor {
using SafeERC20 for IERC20;
@@ -14,8 +15,16 @@ contract UniswapV2Executor is IExecutor {
bytes32 internal constant POOL_INIT_CODE_HASH =
0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f;
address private constant FACTORY =
0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f;
address public immutable factory;
address private immutable self;
constructor(address _factory) {
if (_factory == address(0)) {
revert UniswapV2Executor__InvalidFactory();
}
factory = _factory;
self = address(this);
}
// slither-disable-next-line locked-ether
function swap(uint256 givenAmount, bytes calldata data)
@@ -94,7 +103,7 @@ contract UniswapV2Executor is IExecutor {
uint256(
keccak256(
abi.encodePacked(
hex"ff", FACTORY, salt, POOL_INIT_CODE_HASH
hex"ff", factory, salt, POOL_INIT_CODE_HASH
)
)
)

View File

@@ -47,7 +47,8 @@ contract Constants is Test, BaseConstants {
address USDC_WBTC_POOL = 0x004375Dff511095CC5A197A54140a24eFEF3A416;
// Uniswap v3
address USV3_FACTORY = 0x1F98431c8aD98523631AE4a59f267346ea31F984;
address USV3_FACTORY_ETHEREUM = 0x1F98431c8aD98523631AE4a59f267346ea31F984;
address USV2_FACTORY_ETHEREUM = 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f;
address DAI_WETH_USV3 = 0xC2e9F25Be6257c210d7Adf0D4Cd6E3E881ba25f8;
// Uniswap universal router

View File

@@ -44,7 +44,8 @@ contract TychoRouterTestSetup is Test, Constants {
vm.createSelectFork(vm.rpcUrl("mainnet"), forkBlock);
vm.startPrank(ADMIN);
address factoryV3 = USV3_FACTORY;
address factoryV3 = USV3_FACTORY_ETHEREUM;
address factoryV2 = USV2_FACTORY_ETHEREUM;
address poolManagerAddress = 0x000000000004444c5dc75cB358380D2e3dE08A90;
IPoolManager poolManager = IPoolManager(poolManagerAddress);
tychoRouter = new TychoRouterExposed(PERMIT2_ADDRESS, WETH_ADDR);
@@ -59,7 +60,7 @@ contract TychoRouterTestSetup is Test, Constants {
deployDummyContract();
vm.stopPrank();
usv2Executor = new UniswapV2Executor();
usv2Executor = new UniswapV2Executor(factoryV2);
usv3Executor = new UniswapV3Executor(factoryV3);
usv4Executor = new UniswapV4Executor(poolManager);
vm.startPrank(EXECUTOR_SETTER);

View File

@@ -6,6 +6,8 @@ import {Test} from "../../lib/forge-std/src/Test.sol";
import {Constants} from "../Constants.sol";
contract UniswapV2ExecutorExposed is UniswapV2Executor {
constructor(address _factory) UniswapV2Executor(_factory) {}
function decodeParams(bytes calldata data)
external
pure
@@ -42,7 +44,7 @@ contract FakeUniswapV2Pool {
}
}
contract UniswapV2ExecutorTest is UniswapV2ExecutorExposed, Test, Constants {
contract UniswapV2ExecutorTest is Test, Constants {
using SafeERC20 for IERC20;
UniswapV2ExecutorExposed uniswapV2Exposed;
@@ -52,7 +54,7 @@ contract UniswapV2ExecutorTest is UniswapV2ExecutorExposed, Test, Constants {
function setUp() public {
uint256 forkBlock = 17323404;
vm.createSelectFork(vm.rpcUrl("mainnet"), forkBlock);
uniswapV2Exposed = new UniswapV2ExecutorExposed();
uniswapV2Exposed = new UniswapV2ExecutorExposed(USV2_FACTORY_ETHEREUM);
}
function testDecodeParams() public view {

View File

@@ -44,7 +44,7 @@ contract UniswapV3ExecutorTest is Test, Constants {
uint256 forkBlock = 17323404;
vm.createSelectFork(vm.rpcUrl("mainnet"), forkBlock);
uniswapV3Exposed = new UniswapV3ExecutorExposed(USV3_FACTORY);
uniswapV3Exposed = new UniswapV3ExecutorExposed(USV3_FACTORY_ETHEREUM);
}
function testDecodeParams() public view {