Skip to content

Commit

Permalink
merge dev
Browse files Browse the repository at this point in the history
  • Loading branch information
hensha256 committed Aug 21, 2024
2 parents 54ed723 + 5486943 commit e42e2eb
Show file tree
Hide file tree
Showing 7 changed files with 520 additions and 44 deletions.
2 changes: 1 addition & 1 deletion contracts/UniversalRouter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,6 @@ contract UniversalRouter is IUniversalRouter, Dispatcher {

/// @notice To receive ETH from WETH
receive() external payable {
if (msg.sender != address(WETH9)) revert InvalidEthSender();
if (msg.sender != address(WETH9) && msg.sender != address(poolManager)) revert InvalidEthSender();
}
}
6 changes: 3 additions & 3 deletions contracts/base/Dispatcher.sol
Original file line number Diff line number Diff line change
Expand Up @@ -177,12 +177,12 @@ abstract contract Dispatcher is Payments, V2SwapRouter, V3SwapRouter, V4SwapRout
} else if (command == Commands.WRAP_ETH) {
// equivalent: abi.decode(inputs, (address, uint256))
address recipient;
uint256 amountMin;
uint256 amount;
assembly {
recipient := calldataload(inputs.offset)
amountMin := calldataload(add(inputs.offset, 0x20))
amount := calldataload(add(inputs.offset, 0x20))
}
Payments.wrapETH(map(recipient), amountMin);
Payments.wrapETH(map(recipient), amount);
} else if (command == Commands.UNWRAP_WETH) {
// equivalent: abi.decode(inputs, (address, uint256))
address recipient;
Expand Down
104 changes: 98 additions & 6 deletions test/integration-tests/UniswapMixed.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,19 @@ import type { Contract } from '@ethersproject/contracts'
import { Pair } from '@uniswap/v2-sdk'
import { expect } from './shared/expect'
import { BigNumber } from 'ethers'
import { IPermit2, UniversalRouter } from '../../typechain'
import { IPermit2, PoolManager, PositionManager, UniversalRouter } from '../../typechain'
import { abi as TOKEN_ABI } from '../../artifacts/solmate/src/tokens/ERC20.sol/ERC20.json'
import { resetFork, WETH, DAI, USDC, USDT, PERMIT2 } from './shared/mainnetForkHelpers'
import {
ADDRESS_THIS,
ALICE_ADDRESS,
CONTRACT_BALANCE,
DEADLINE,
ETH_ADDRESS,
MAX_UINT,
MAX_UINT160,
MSG_SENDER,
OPEN_DELTA,
SOURCE_MSG_SENDER,
SOURCE_ROUTER,
} from './shared/constants'
Expand All @@ -24,9 +26,19 @@ import hre from 'hardhat'
import { getPermitBatchSignature } from './shared/protocolHelpers/permit2'
import { encodePathExactInput, encodePathExactOutput } from './shared/swapRouter02Helpers'
import { executeRouter } from './shared/executeRouter'
import { Actions, V4Planner } from './shared/v4Planner'
import {
addLiquidityToV4Pool,
DAI_USDC,
deployV4PoolManager,
encodeMultihopExactInPath,
ETH_USDC,
initializeV4Pool,
USDC_WETH,
} from './shared/v4Helpers'
const { ethers } = hre

describe('Uniswap V2 and V3 Tests:', () => {
describe('Uniswap V2, V3, and V4 Tests:', () => {
let alice: SignerWithAddress
let bob: SignerWithAddress
let router: UniversalRouter
Expand All @@ -35,6 +47,12 @@ describe('Uniswap V2 and V3 Tests:', () => {
let wethContract: Contract
let usdcContract: Contract
let planner: RoutePlanner
let v4Planner: V4Planner
let v4PoolManager: PoolManager
let v4PositionManager: PositionManager

// current market ETH price at block
const USD_ETH_PRICE = 3820

beforeEach(async () => {
await resetFork()
Expand All @@ -48,13 +66,20 @@ describe('Uniswap V2 and V3 Tests:', () => {
wethContract = new ethers.Contract(WETH.address, TOKEN_ABI, bob)
usdcContract = new ethers.Contract(USDC.address, TOKEN_ABI, bob)
permit2 = PERMIT2.connect(bob) as IPermit2
router = (await deployUniversalRouter()) as UniversalRouter

v4PoolManager = (await deployV4PoolManager()).connect(bob) as PoolManager
router = (await deployUniversalRouter(v4PoolManager.address)).connect(bob) as UniversalRouter

v4PositionManager = (await ethers.getContractAt('PositionManager', await router.V4_POSITION_MANAGER())).connect(
bob
) as PositionManager
planner = new RoutePlanner()
v4Planner = new V4Planner()

// alice gives bob some tokens
await daiContract.connect(alice).transfer(bob.address, expandTo18DecimalsBN(100000))
await wethContract.connect(alice).transfer(bob.address, expandTo18DecimalsBN(100))
await usdcContract.connect(alice).transfer(bob.address, expandTo6DecimalsBN(100000))
await daiContract.connect(alice).transfer(bob.address, expandTo18DecimalsBN(1000000))
await wethContract.connect(alice).transfer(bob.address, expandTo18DecimalsBN(1000))
await usdcContract.connect(alice).transfer(bob.address, expandTo6DecimalsBN(50000000))

// Bob max-approves the permit2 contract to access his DAI and WETH
await daiContract.connect(bob).approve(permit2.address, MAX_UINT)
Expand All @@ -65,6 +90,21 @@ describe('Uniswap V2 and V3 Tests:', () => {
await permit2.approve(DAI.address, router.address, MAX_UINT160, DEADLINE)
await permit2.approve(WETH.address, router.address, MAX_UINT160, DEADLINE)
await permit2.approve(USDC.address, router.address, MAX_UINT160, DEADLINE)

// for setting up pools, bob gives position manager approval on permit2
await permit2.approve(DAI.address, v4PositionManager.address, MAX_UINT160, DEADLINE)
await permit2.approve(WETH.address, v4PositionManager.address, MAX_UINT160, DEADLINE)
await permit2.approve(USDC.address, v4PositionManager.address, MAX_UINT160, DEADLINE)

// bob initializes 3 v4 pools
await initializeV4Pool(v4PoolManager, USDC_WETH.poolKey, USDC_WETH.price)
await initializeV4Pool(v4PoolManager, DAI_USDC.poolKey, DAI_USDC.price)
await initializeV4Pool(v4PoolManager, ETH_USDC.poolKey, ETH_USDC.price)

// bob adds liquidity to the pools
await addLiquidityToV4Pool(v4PositionManager, USDC_WETH, expandTo18DecimalsBN(2).toString(), bob)
await addLiquidityToV4Pool(v4PositionManager, DAI_USDC, expandTo18DecimalsBN(400).toString(), bob)
await addLiquidityToV4Pool(v4PositionManager, ETH_USDC, expandTo18DecimalsBN(0.1).toString(), bob)
})

describe('Interleaving routes', () => {
Expand Down Expand Up @@ -516,6 +556,58 @@ describe('Uniswap V2 and V3 Tests:', () => {
expect(ethBalanceAfter.sub(ethBalanceBefore)).to.eq(fullAmountOut.sub(gasSpent))
})

it('ERC20 --> ERC20 split V4 and V4 different routes, with wrap, aggregate slippage', async () => {
// route 1: DAI -> USDC -> WETH
// route 2: DAI -> USDC -> ETH, then router wraps ETH -> WETH
const route1 = [DAI_USDC.poolKey, USDC_WETH.poolKey]
const route2 = [DAI_USDC.poolKey, ETH_USDC.poolKey]
const v4AmountIn1 = expandTo18DecimalsBN(100)
const v4AmountIn2 = expandTo18DecimalsBN(150)
const aggregateMinOut = expandTo18DecimalsBN(250 / Math.floor(USD_ETH_PRICE * 1.01))

let currencyIn = daiContract.address
// add first split to v4 planner
v4Planner.addAction(Actions.SWAP_EXACT_IN, [
{
currencyIn,
path: encodeMultihopExactInPath(route1, currencyIn),
amountIn: v4AmountIn1,
amountOutMinimum: 0,
},
])
// add second split to v4 planner
v4Planner.addAction(Actions.SWAP_EXACT_IN, [
{
currencyIn,
path: encodeMultihopExactInPath(route2, currencyIn),
amountIn: v4AmountIn2,
amountOutMinimum: 0,
},
])
// settle all DAI with no limit
v4Planner.addAction(Actions.SETTLE_ALL, [currencyIn, v4AmountIn1.add(v4AmountIn2)])
// take all the WETH and all the ETH into the router
v4Planner.addAction(Actions.TAKE, [WETH.address, ADDRESS_THIS, OPEN_DELTA])
v4Planner.addAction(Actions.TAKE, [ETH_ADDRESS, ADDRESS_THIS, OPEN_DELTA])

planner.addCommand(CommandType.V4_SWAP, [v4Planner.actions, v4Planner.params])
// wrap all the ETH into WETH
planner.addCommand(CommandType.WRAP_ETH, [ADDRESS_THIS, CONTRACT_BALANCE])
// now we can send the WETH to the user, with aggregate slippage check
planner.addCommand(CommandType.SWEEP, [WETH.address, MSG_SENDER, aggregateMinOut])

const { daiBalanceBefore, daiBalanceAfter, wethBalanceBefore, wethBalanceAfter } = await executeRouter(
planner,
bob,
router,
wethContract,
daiContract,
usdcContract
)
expect(wethBalanceAfter.sub(wethBalanceBefore)).to.be.gte(aggregateMinOut)
expect(daiBalanceBefore.sub(daiBalanceAfter)).to.be.eq(v4AmountIn1.add(v4AmountIn2))
})

describe('Batch reverts', () => {
let subplan: RoutePlanner
const planOneTokens = [DAI.address, WETH.address]
Expand Down
Loading

0 comments on commit e42e2eb

Please sign in to comment.