Skip to content
This repository has been archived by the owner on Nov 11, 2022. It is now read-only.

Commit

Permalink
Merge pull request #30 from rayeaster/feat-v3
Browse files Browse the repository at this point in the history
make findOptimalSwap view
  • Loading branch information
GalloDaSballo authored Aug 1, 2022
2 parents b4915b3 + f23820d commit a419a60
Show file tree
Hide file tree
Showing 12 changed files with 146 additions and 78 deletions.
2 changes: 1 addition & 1 deletion contracts/CowSwapSeller.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ struct Quote {
uint256[] poolFees; // specific pool fees involved in the optimal swap path, typically in Uniswap V3
}
interface OnChainPricing {
function findOptimalSwap(address tokenIn, address tokenOut, uint256 amountIn) external returns (Quote memory);
function findOptimalSwap(address tokenIn, address tokenOut, uint256 amountIn) external view returns (Quote memory);
}
// END OnchainPricing

Expand Down
4 changes: 2 additions & 2 deletions contracts/OnChainPricingMainnet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -188,13 +188,13 @@ contract OnChainPricingMainnet {
/// @param tokenIn - The token you want to sell
/// @param tokenOut - The token you want to buy
/// @param amountIn - The amount of token you want to sell
function findOptimalSwap(address tokenIn, address tokenOut, uint256 amountIn) external virtual returns (Quote memory) {
function findOptimalSwap(address tokenIn, address tokenOut, uint256 amountIn) external view virtual returns (Quote memory) {
return _findOptimalSwap(tokenIn, tokenOut, amountIn);
}

/// @dev View function for testing the routing of the strategy
/// See {findOptimalSwap}
function _findOptimalSwap(address tokenIn, address tokenOut, uint256 amountIn) internal returns (Quote memory) {
function _findOptimalSwap(address tokenIn, address tokenOut, uint256 amountIn) internal view returns (Quote memory) {
bool wethInvolved = (tokenIn == WETH || tokenOut == WETH);
uint256 length = wethInvolved? 5 : 7; // Add length you need

Expand Down
2 changes: 1 addition & 1 deletion contracts/OnChainPricingMainnetLenient.sol
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ contract OnChainPricingMainnetLenient is OnChainPricingMainnet {
// === PRICING === //

/// @dev View function for testing the routing of the strategy
function findOptimalSwap(address tokenIn, address tokenOut, uint256 amountIn) external override returns (Quote memory q) {
function findOptimalSwap(address tokenIn, address tokenOut, uint256 amountIn) external view override returns (Quote memory q) {
q = _findOptimalSwap(tokenIn, tokenOut, amountIn);
q.amountOut = q.amountOut * (MAX_BPS - slippage) / MAX_BPS;
}
Expand Down
2 changes: 1 addition & 1 deletion contracts/OnChainSwapMainnet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ struct Quote {
}

interface OnChainPricing {
function findOptimalSwap(address tokenIn, address tokenOut, uint256 amountIn) external returns (Quote memory);
function findOptimalSwap(address tokenIn, address tokenOut, uint256 amountIn) external view returns (Quote memory);
}

/// @dev Mainnet Version of swap for various on-chain dex
Expand Down
42 changes: 42 additions & 0 deletions contracts/tests/PricerWrapper.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
pragma solidity 0.8.10;
pragma experimental ABIEncoderV2;

enum SwapType {
CURVE, //0
UNIV2, //1
SUSHI, //2
UNIV3, //3
UNIV3WITHWETH, //4
BALANCER, //5
BALANCERWITHWETH //6
}

// Onchain Pricing Interface
struct Quote {
SwapType name;
uint256 amountOut;
bytes32[] pools; // specific pools involved in the optimal swap path
uint256[] poolFees; // specific pool fees involved in the optimal swap path, typically in Uniswap V3
}
interface OnChainPricing {
function isPairSupported(address tokenIn, address tokenOut, uint256 amountIn) external view returns (bool);
function findOptimalSwap(address tokenIn, address tokenOut, uint256 amountIn) external view returns (Quote memory);
}
// END OnchainPricing

contract PricerWrapper {
address public pricer;
constructor(address _pricer) {
pricer = _pricer;
}

function isPairSupported(address tokenIn, address tokenOut, uint256 amountIn) external view returns (bool) {
return OnChainPricing(pricer).isPairSupported(tokenIn, tokenOut, amountIn);
}

function findOptimalSwap(address tokenIn, address tokenOut, uint256 amountIn) external view returns (uint256, Quote memory) {
uint256 _gasBefore = gasleft();
Quote memory q = OnChainPricing(pricer).findOptimalSwap(tokenIn, tokenOut, amountIn);
return (_gasBefore - gasleft(), q);
}
}
7 changes: 7 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@
def swapexecutor():
return OnChainSwapMainnet.deploy({"from": accounts[0]})

@pytest.fixture
def pricerwrapper():
univ3simulator = UniV3SwapSimulator.deploy({"from": accounts[0]})
balancerV2Simulator = BalancerSwapSimulator.deploy({"from": accounts[0]})
pricer = OnChainPricingMainnet.deploy(univ3simulator.address, balancerV2Simulator.address, {"from": accounts[0]})
return PricerWrapper.deploy(pricer.address, {"from": accounts[0]})

@pytest.fixture
def pricer():
univ3simulator = UniV3SwapSimulator.deploy({"from": accounts[0]})
Expand Down
67 changes: 37 additions & 30 deletions tests/gas_benchmark/benchmark_pricer_gas.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,80 +8,87 @@
Rename the file to test_benchmark_pricer_gas.py to make this part of the testing suite if required
"""

def test_gas_only_uniswap_v2(oneE18, weth, pricer):
def test_gas_only_uniswap_v2(oneE18, weth, pricerwrapper):
pricer = pricerwrapper
token = "0xBC7250C8c3eCA1DfC1728620aF835FCa489bFdf3" # some swap (GM-WETH) only in Uniswap V2
## 1e18
sell_count = 100000000
sell_amount = sell_count * 1000000000 ## 1e9

tx = pricer.findOptimalSwap(token, weth.address, sell_amount)
assert tx.return_value[0] == 1 ## UNIV2
assert tx.return_value[1] > 0
assert tx.gas_used <= 80000 ## 73925 in test simulation
assert tx[1][0] == 1 ## UNIV2
assert tx[1][1] > 0
assert tx[0] <= 80000 ## 73925 in test simulation

def test_gas_uniswap_v2_sushi(oneE18, weth, pricer):
def test_gas_uniswap_v2_sushi(oneE18, weth, pricerwrapper):
pricer = pricerwrapper
token = "0x2e9d63788249371f1DFC918a52f8d799F4a38C94" # some swap (TOKE-WETH) only in Uniswap V2 & SushiSwap
## 1e18
sell_count = 5000
sell_amount = sell_count * oneE18 ## 1e18

tx = pricer.findOptimalSwap(token, weth.address, sell_amount)
assert (tx.return_value[0] == 1 or tx.return_value[0] == 2) ## UNIV2 or SUSHI
assert tx.return_value[1] > 0
assert tx.gas_used <= 90000 ## 83158 in test simulation
assert (tx[1][0] == 1 or tx[1][0] == 2) ## UNIV2 or SUSHI
assert tx[1][1] > 0
assert tx[0] <= 90000 ## 83158 in test simulation

def test_gas_only_balancer_v2(oneE18, weth, aura, pricer):
def test_gas_only_balancer_v2(oneE18, weth, aura, pricerwrapper):
pricer = pricerwrapper
token = aura # some swap (AURA-WETH) only in Balancer V2
## 1e18
sell_count = 2000
sell_count = 8000
sell_amount = sell_count * oneE18 ## 1e18

tx = pricer.findOptimalSwap(token, weth.address, sell_amount)
assert tx.return_value[0] == 5 ## BALANCER
assert tx.return_value[1] > 0
assert tx.gas_used <= 110000 ## 101190 in test simulation
assert tx[1][0] == 5 ## BALANCER
assert tx[1][1] > 0
assert tx[0] <= 110000 ## 101190 in test simulation

def test_gas_only_balancer_v2_with_weth(oneE18, wbtc, aura, pricer):
def test_gas_only_balancer_v2_with_weth(oneE18, wbtc, aura, pricerwrapper):
pricer = pricerwrapper
token = aura # some swap (AURA-WETH-WBTC) only in Balancer V2 via WETH in between as connector
## 1e18
sell_count = 2000
sell_count = 8000
sell_amount = sell_count * oneE18 ## 1e18

tx = pricer.findOptimalSwap(token, wbtc.address, sell_amount)
assert tx.return_value[0] == 6 ## BALANCERWITHWETH
assert tx.return_value[1] > 0
assert tx.gas_used <= 170000 ## 161690 in test simulation
assert tx[1][0] == 6 ## BALANCERWITHWETH
assert tx[1][1] > 0
assert tx[0] <= 170000 ## 161690 in test simulation

def test_gas_only_uniswap_v3(oneE18, weth, pricer):
def test_gas_only_uniswap_v3(oneE18, weth, pricerwrapper):
pricer = pricerwrapper
token = "0xf4d2888d29D722226FafA5d9B24F9164c092421E" # some swap (LOOKS-WETH) only in Uniswap V3
## 1e18
sell_count = 600000
sell_amount = sell_count * oneE18 ## 1e18

tx = pricer.findOptimalSwap(token, weth.address, sell_amount)
assert tx.return_value[0] == 3 ## UNIV3
assert tx.return_value[1] > 0
assert tx.gas_used <= 160000 ## 158204 in test simulation
assert tx[1][0] == 3 ## UNIV3
assert tx[1][1] > 0
assert tx[0] <= 160000 ## 158204 in test simulation

def test_gas_only_uniswap_v3_with_weth(oneE18, wbtc, pricer):
def test_gas_only_uniswap_v3_with_weth(oneE18, wbtc, pricerwrapper):
pricer = pricerwrapper
token = "0xf4d2888d29D722226FafA5d9B24F9164c092421E" # some swap (LOOKS-WETH-WBTC) only in Uniswap V3 via WETH in between as connector
## 1e18
sell_count = 600000
sell_amount = sell_count * oneE18 ## 1e18

tx = pricer.findOptimalSwap(token, wbtc.address, sell_amount)
assert tx.return_value[0] == 4 ## UNIV3WITHWETH
assert tx.return_value[1] > 0
assert tx.gas_used <= 230000 ## 227498 in test simulation
assert tx[1][0] == 4 ## UNIV3WITHWETH
assert tx[1][1] > 0
assert tx[0] <= 230000 ## 227498 in test simulation

def test_gas_almost_everything(oneE18, wbtc, weth, pricer):
def test_gas_almost_everything(oneE18, wbtc, weth, pricerwrapper):
pricer = pricerwrapper
token = weth # some swap (WETH-WBTC) almost in every DEX, the most gas-consuming scenario
## 1e18
sell_count = 10
sell_amount = sell_count * oneE18 ## 1e18

tx = pricer.findOptimalSwap(token, wbtc.address, sell_amount)
assert (tx.return_value[0] <= 3 or tx.return_value[0] == 5) ## CURVE or UNIV2 or SUSHI or UNIV3 or BALANCER
assert tx.return_value[1] > 0
assert tx.gas_used <= 210000 ## 200229 in test simulation
assert (tx[1][0] <= 3 or tx[1][0] == 5) ## CURVE or UNIV2 or SUSHI or UNIV3 or BALANCER
assert tx[1][1] > 0
assert tx[0] <= 210000 ## 200229 in test simulation

7 changes: 4 additions & 3 deletions tests/gas_benchmark/benchmark_token_coverage.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,13 @@
]

@pytest.mark.parametrize("token,count", TOP_DECIMAL18_TOKENS)
def test_token_decimal18(oneE18, weth, token, count, pricer):
def test_token_decimal18(oneE18, weth, token, count, pricerwrapper):
pricer = pricerwrapper
sell_token = token
## 1e18
sell_count = count
sell_amount = sell_count * oneE18 ## 1e18

quote = pricer.findOptimalSwap.call(sell_token, weth.address, sell_amount)
assert quote[1] > 0
quote = pricer.findOptimalSwap(sell_token, weth.address, sell_amount)
assert quote[1][1] > 0

Loading

0 comments on commit a419a60

Please sign in to comment.