Skip to content

Commit

Permalink
fix(universal-router-sdk): Strip unviersal-router-sdk of NFT commands…
Browse files Browse the repository at this point in the history
… to match new UR contracts (#83)

Co-authored-by: gretzke <[email protected]>
  • Loading branch information
ewilz and gretzke authored Sep 26, 2024
1 parent ce9ca55 commit dd4d598
Show file tree
Hide file tree
Showing 44 changed files with 150 additions and 3,233 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/monorepo-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
- name: ✅ Checkout
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744
with:
submodules: "true"
submodules: "recursive"
fetch-depth: 2

- name: 💽 Node and Caching
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,6 @@
path = sdks/universal-router-sdk/lib/openzeppelin-contracts
url = https://github.com/openzeppelin/openzeppelin-contracts
branch = v4.8.0
[submodule "sdks/universal-router-sdk/lib/universal-router"]
path = sdks/universal-router-sdk/lib/universal-router
url = https://github.com/Uniswap/universal-router
80 changes: 3 additions & 77 deletions sdks/universal-router-sdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,7 @@ This SDK facilitates interactions with the contracts in [Universal Router](https
## Usage
Install latest version of universal-router-sdk. Then import the corresponding Trade class and Data object for each protocol you'd like to interact with.

### Trading NFTs
warning: `swapNFTCallParameters()` to be deprecated in favor of `swapCallParameters()`
```typescript
import {
LooksRareTrade,
LooksRareData,
SeaportTrade,
SeaportData
} from "@uniswap/universal-router-sdk";

// Each protocol data object contains 1 call to that protocol. Some protocols can fit
// many NFT purchase within 1 call, like seaport. Others require multiple calls per NFT (like LooksRare).
const looksRareTrades = new LooksRareTrade([looksrareData1, looksrareData2])
const seaportTrades = new SeaportTrade([seaportData1])

// Use the raw calldata and value returned to call into Universal Swap Router contracts
// Trades will happen in the order that they are handed in
const { calldata, value } = SwapRouter.swapCallParameters([looksRareTrades, seaportTrades])
```

### Trading ERC20s on Uniswap
### Trading on Uniswap
warning: `swapERC20CallParameters()` to be deprecated in favor of `swapCallParameters()`
```typescript
import { TradeType } from '@uniswap/sdk-core'
Expand All @@ -33,63 +13,9 @@ import { Trade as V3TradeSDK } from '@uniswap/v3-sdk'
import { MixedRouteTrade, MixedRouteSDK, Trade as RouterTrade } from '@uniswap/router-sdk'

const options = { slippageTolerance, recipient }
const routerTrade = new UniswapTrade(
new RouterTrade({ v2Routes, v3Routes, mixedRoutes, tradeType: TradeType.EXACT_INPUT },
options
)
// Use the raw calldata and value returned to call into Universal Swap Router contracts
const { calldata, value } = SwapRouter.swapCallParameters(routerTrade)
```
### Using Uniswap for ERC20 NFT Trades
Send ETH to the router by trading an ERC20 for ETH with a Uniswap Trade and encoding the swap recipient as `ROUTER_AS_RECIPIENT` in the trade. Then subsequently list the NFT trades to use the ETH output to buy NFTs. Trades happen in the order they are listed.
Use `trade_type: TradeType.EXACT_OUTPUT` to cover the entire NFT price, alternatively the transaction will send supplemental ETH to fulfill the entire price if the swap does not cover it in full. Keep in mind that `TradeType.EXACT_INPUT` trades are subject to slippage on output, and ETH will be sent to cover potential slippage and any remaining ETH will be returned to sender.
```typescript
import { TradeType } from '@uniswap/sdk-core'
import { Trade as V2TradeSDK } from '@uniswap/v2-sdk'
import { Trade as V3TradeSDK } from '@uniswap/v3-sdk'
import { MixedRouteTrade, MixedRouteSDK, Trade as RouterTrade } from '@uniswap/router-sdk'
import {
ROUTER_AS_RECIPIENT,
UniswapTrade,
LooksRareTrade,
LooksRareData,
SeaportTrade,
SeaportData
} from "@uniswap/universal-router-sdk";

const looksRareTrades = new LooksRareTrade([looksrareData1, looksrareData2])
const seaportTrades = new SeaportTrade([seaportData1])
// WARNING: never send funds to ROUTER_AS_RECIPIENT unless it is ETH that will be used in NFT trades, otherwise funds are lost.
const uniswapTrade = new UniswapTrade(
new RouterTrade({ v2Routes, v3Routes, mixedRoutes, tradeType: TradeType.EXACT_OUTPUT }),
{ slippageTolerance, recipient: ROUTER_AS_RECIPIENT}
)
// Use the raw calldata and value returned to call into Universal Swap Router contracts
const { calldata, value } = SwapRouter.swapCallParameters([uniswapTrade, seaportTrades, looksRareTrades])
```
### Using WETH for NFT Trades
The current router purchases all NFTs with ETH, but you can send WETH to the router to be unwrapped for ETH right before the NFT commands. Similar to ERC20 Uniswap Trades for NFTs, supplemental ETH will be sent in the transaction if the WETH amount will not cover the NFT buys. You can also use ERC20s and WETH to cover the transaction by including both commands before the NFT purchase.
```typescript
import {
ROUTER_AS_RECIPIENT,
UniswapTrade,
LooksRareTrade,
LooksRareData,
SeaportTrade,
SeaportData
} from "@uniswap/universal-router-sdk";

const looksRareTrades = new LooksRareTrade([looksrareData1, looksrareData2])
const seaportTrades = new SeaportTrade([seaportData1])
// if no Permit needed, omit the third var of type Permit2Permit
const unwrapWETH = new UnwrapWETH(amountWETH, chainId, optionalPermit2Params)

const routerTrade = new RouterTrade({ v2Routes, v3Routes, mixedRoutes, tradeType: TradeType.EXACT_INPUT })
// Use the raw calldata and value returned to call into Universal Swap Router contracts
const { calldata, value } = SwapRouter.swapCallParameters([unwrapWETH, seaportTrades, looksRareTrades])
const { calldata, value } = SwapRouter.swapCallParameters(routerTrade, options)
```

## Running this package
Expand Down
5 changes: 3 additions & 2 deletions sdks/universal-router-sdk/foundry.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
[profile.default]
solc = "0.8.17"
fs_permissions = [{ access = "read", path = "./permit2/out/Permit2.sol/Permit2.json"}, { access = "read", path = "./test/forge/interop.json"}]
solc = "0.8.26"
fs_permissions = [{ access = "read", path = "./permit2/out/Permit2.sol/Permit2.json"}, { access = "read", path = "./test/forge/interop.json"}, { access = "read", path = "./test/forge/bin/permit2.bin"}]
src = "./test/forge"
via_ir = true
evm_version = "cancun"
2 changes: 1 addition & 1 deletion sdks/universal-router-sdk/lib/permit2
Submodule permit2 updated 41 files
+1 −1 .forge-snapshots/batchTransferFrom.snap
+1 −1 .forge-snapshots/batchTransferFromMultiToken.snap
+1 −0 .forge-snapshots/permit2 + transferFrom2 with WETH9's mainnet address.snap
+1 −0 .forge-snapshots/permit2 + transferFrom2 with a non EIP-2612 native token with fallback.snap
+1 −1 .forge-snapshots/permit2 + transferFrom2 with a non EIP-2612 native token.snap
+1 −1 .forge-snapshots/permit2 + transferFrom2 with an EIP-2612 native token.snap
+1 −0 .forge-snapshots/simplePermit2 + transferFrom2 with a non EIP-2612 native token.snap
+113 −103 .gas-snapshot
+17 −3 README.md
+1 −1 lib/forge-std
+16 −0 package.json
+1 −1 src/AllowanceTransfer.sol
+4 −2 src/EIP712.sol
+9 −4 src/interfaces/IAllowanceTransfer.sol
+1 −1 src/interfaces/IDAIPermit.sol
+6 −0 src/interfaces/IEIP712.sol
+1 −1 src/interfaces/IERC1271.sol
+11 −0 src/interfaces/IPermit2.sol
+4 −2 src/interfaces/ISignatureTransfer.sol
+64 −32 src/libraries/Permit2Lib.sol
+5 −5 test/AllowanceTransferInvariants.t.sol
+3 −3 test/AllowanceTransferTest.t.sol
+3 −2 test/AllowanceUnitTest.sol
+2 −2 test/CompactSignature.t.sol
+1 −1 test/EIP712.t.sol
+1 −1 test/NonceBitmap.t.sol
+187 −2 test/Permit2Lib.t.sol
+1 −1 test/SignatureTransfer.t.sol
+1 −1 test/TypehashGeneration.t.sol
+3 −1 test/actors/Permitter.sol
+1 −1 test/integration/Argent.t.sol
+1 −1 test/integration/GnosisSafe.t.sol
+1 −1 test/integration/MainnetToken.t.sol
+118 −0 test/mocks/MockFallbackERC20.sol
+0 −2 test/mocks/MockHash.sol
+33 −11 test/mocks/MockPermit2Lib.sol
+23 −0 test/utils/DeployPermit2.sol
+81 −0 test/utils/DeployPermit2.t.sol
+0 −36 test/utils/InvariantTest.sol
+13 −12 test/utils/PermitSignature.sol
+1 −1 test/utils/TokenProvider.sol
1 change: 1 addition & 0 deletions sdks/universal-router-sdk/lib/universal-router
Submodule universal-router added at 5e9f4c
10 changes: 6 additions & 4 deletions sdks/universal-router-sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,24 @@
"build": "tsdx build",
"docs": "typedoc",
"forge:fix": "forge fmt",
"install:ur": "cd node_modules/@uniswap/universal-router && forge install",
"lint": "yarn prettier",
"lint:fix": "yarn prettier:fix && yarn forge:fix",
"prettier": "prettier --check '**/*.ts' && prettier --check '**/*.json'",
"prettier:fix": "prettier --write '**/*.ts' && prettier --write '**/*.json'",
"release": "semantic-release",
"test": "yarn test:hardhat && yarn test:forge",
"test:forge": "yarn install:ur && forge test",
"test:forge": "forge test",
"test:hardhat": "env TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\" }' hardhat test"
},
"dependencies": {
"@openzeppelin/contracts": "4.7.0",
"@uniswap/permit2-sdk": "^1.3.0",
"@uniswap/router-sdk": "^1.10.0",
"@uniswap/router-sdk": "^1.11.0",
"@uniswap/sdk-core": "^5.3.1",
"@uniswap/universal-router": "1.6.0",
"@uniswap/universal-router": "2.0.0-beta.1",
"@uniswap/v2-core": "^1.0.1",
"@uniswap/v2-sdk": "^4.4.1",
"@uniswap/v3-core": "1.0.0",
"@uniswap/v3-sdk": "^3.13.1",
"@uniswap/v4-sdk": "^1.0.0",
"bignumber.js": "^9.0.2",
Expand Down
11 changes: 7 additions & 4 deletions sdks/universal-router-sdk/remappings.txt
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
@ensdomains/=node_modules/@uniswap/universal-router/node_modules/@ensdomains/
@openzeppelin/=lib/openzeppelin-contracts/
@uniswap/=node_modules/@uniswap/
base64-sol/=node_modules/base64-sol/
ds-test/=lib/forge-std/lib/ds-test/src/
forge-std/=lib/forge-std/src/
hardhat/=node_modules/@uniswap/universal-router/node_modules/hardhat/
openzeppelin-contracts=lib/openzeppelin-contracts/
permit2/=lib/permit2/
universal-router/=node_modules/@uniswap/universal-router/contracts
universal-router/=lib/universal-router/contracts
@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/
@uniswap/v3-periphery/=lib/universal-router/lib/v3-periphery/
@uniswap/v4-periphery/=lib/universal-router/lib/v4-periphery/
@uniswap/v4-core/=lib/universal-router/lib/v4-periphery/lib/v4-core/
@uniswap/v2-core/=node_modules/@uniswap/v2-core/
@uniswap/v3-core/=node_modules/@uniswap/v3-core/
solmate/=lib/solmate/
v2-core/=node_modules/@uniswap/universal-router/lib/v2-core/
v3-core/=node_modules/@uniswap/universal-router/lib/v3-core/
5 changes: 2 additions & 3 deletions sdks/universal-router-sdk/src/entities/Command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@ export type TradeConfig = {
allowRevert: boolean
}

export enum RouterTradeType {
export enum RouterActionType {
UniswapTrade = 'UniswapTrade',
NFTTrade = 'NFTTrade',
UnwrapWETH = 'UnwrapWETH',
}

// interface for entities that can be encoded as a Universal Router command
export interface Command {
tradeType: RouterTradeType
tradeType: RouterActionType
encode(planner: RoutePlanner, config: TradeConfig): void
}
68 changes: 0 additions & 68 deletions sdks/universal-router-sdk/src/entities/NFTTrade.ts

This file was deleted.

2 changes: 2 additions & 0 deletions sdks/universal-router-sdk/src/entities/actions/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './uniswap'
export * from './unwrapWETH'
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
} from '@uniswap/router-sdk'
import { Permit2Permit } from '../../utils/inputTokens'
import { Currency, TradeType, CurrencyAmount, Percent } from '@uniswap/sdk-core'
import { Command, RouterTradeType, TradeConfig } from '../Command'
import { Command, RouterActionType, TradeConfig } from '../Command'
import { SENDER_AS_RECIPIENT, ROUTER_AS_RECIPIENT, CONTRACT_BALANCE, ETH_ADDRESS } from '../../utils/constants'
import { encodeFeeBips } from '../../utils/numbers'
import { BigNumber, BigNumberish } from 'ethers'
Expand Down Expand Up @@ -50,12 +50,11 @@ interface Swap<TInput extends Currency, TOutput extends Currency> {
// Wrapper for uniswap router-sdk trade entity to encode swaps for Universal Router
// also translates trade objects from previous (v2, v3) SDKs
export class UniswapTrade implements Command {
readonly tradeType: RouterTradeType = RouterTradeType.UniswapTrade
readonly tradeType: RouterActionType = RouterActionType.UniswapTrade
readonly payerIsUser: boolean

constructor(public trade: RouterTrade<Currency, Currency, TradeType>, public options: SwapOptions) {
if (!!options.fee && !!options.flatFee) throw new Error('Only one fee option permitted')

if (this.inputRequiresWrap) this.payerIsUser = false
else if (this.options.useRouterBalance) this.payerIsUser = false
else this.payerIsUser = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import invariant from 'tiny-invariant'
import { BigNumberish } from 'ethers'
import { RoutePlanner, CommandType } from '../../utils/routerCommands'
import { encodeInputTokenOptions, Permit2Permit } from '../../utils/inputTokens'
import { Command, RouterTradeType, TradeConfig } from '../Command'
import { Command, RouterActionType, TradeConfig } from '../Command'
import { ROUTER_AS_RECIPIENT, WETH_ADDRESS } from '../../utils/constants'

export class UnwrapWETH implements Command {
readonly tradeType: RouterTradeType = RouterTradeType.UnwrapWETH
readonly tradeType: RouterActionType = RouterActionType.UnwrapWETH
readonly permit2Data: Permit2Permit
readonly wethAddress: string
readonly amount: BigNumberish
Expand Down
3 changes: 1 addition & 2 deletions sdks/universal-router-sdk/src/entities/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
export * from './protocols'
export * from './NFTTrade'
export * from './actions'
export * from './Command'
44 changes: 0 additions & 44 deletions sdks/universal-router-sdk/src/entities/protocols/cryptopunk.ts

This file was deleted.

Loading

0 comments on commit dd4d598

Please sign in to comment.