@dhedge/v2-sdk 2.1.8 → 2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +404 -54
- package/dist/config.d.ts +13 -2
- package/dist/entities/pool.d.ts +25 -86
- package/dist/entities/utils.d.ts +15 -0
- package/dist/services/hyperliquid/index.d.ts +22 -0
- package/dist/services/kyberSwap/index.d.ts +1 -1
- package/dist/services/ondo/index.d.ts +5 -0
- package/dist/services/oneInch/index.d.ts +1 -1
- package/dist/services/toros/easySwapper.d.ts +14 -0
- package/dist/services/toros/swapData.d.ts +5 -5
- package/dist/services/uniswap/V3Liquidity.d.ts +2 -2
- package/dist/services/velodrome/liquidity.d.ts +3 -0
- package/dist/test/constants.d.ts +48 -3
- package/dist/test/utils/testingHelper.d.ts +4 -0
- package/dist/types.d.ts +21 -5
- package/dist/utils/contract.d.ts +20 -0
- package/dist/v2-sdk.cjs.development.js +5133 -6641
- package/dist/v2-sdk.cjs.development.js.map +1 -1
- package/dist/v2-sdk.cjs.production.min.js +1 -1
- package/dist/v2-sdk.cjs.production.min.js.map +1 -1
- package/dist/v2-sdk.esm.js +5138 -6641
- package/dist/v2-sdk.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/abi/PoolFactory.json +414 -204
- package/src/abi/PoolLogic.json +160 -134
- package/src/abi/ondo/IOndoGMSwap.json +30 -0
- package/src/config.ts +15 -9
- package/src/entities/pool.ts +56 -253
- package/src/entities/utils.ts +15 -0
- package/src/services/hyperliquid/index.ts +22 -0
- package/src/services/kyberSwap/index.ts +5 -3
- package/src/services/ondo/index.ts +142 -0
- package/src/services/oneInch/index.ts +5 -4
- package/src/services/toros/completeWithdrawal.ts +57 -40
- package/src/services/toros/easySwapper.ts +15 -1
- package/src/services/toros/initWithdrawal.ts +39 -31
- package/src/services/toros/swapData.ts +45 -131
- package/src/services/uniswap/V3Liquidity.ts +3 -24
- package/src/services/velodrome/liquidity.ts +3 -0
- package/src/test/aave.test.ts +99 -70
- package/src/test/aerodrome.test.ts +53 -24
- package/src/test/aerodromeCL.test.ts +64 -30
- package/src/test/arrakis.test.ts +23 -35
- package/src/test/balancer.test.ts +114 -106
- package/src/test/compoundV3.test.ts +45 -29
- package/src/test/constants.ts +56 -11
- package/src/test/cowswap.test.ts +33 -35
- package/src/test/dhedge.test.ts +45 -12
- package/src/test/flatmoney.test.ts +25 -39
- package/src/test/fluid.test.ts +33 -24
- package/src/test/hyperliquid.onchain.test.ts +131 -0
- package/src/test/kyberSwap.test.ts +37 -16
- package/src/test/lyra.test.ts +159 -150
- package/src/test/odos.test.ts +2 -2
- package/src/test/ondo.onchain.test.ts +132 -0
- package/src/test/oneInch.test.ts +36 -22
- package/src/test/pancakeCL.test.ts +72 -31
- package/src/test/pendle.test.ts +94 -54
- package/src/test/{pendleMint.test.ts → pendleMint.onchain.test.ts} +22 -8
- package/src/test/pool.test.ts +152 -95
- package/src/test/toros.onchain.test.ts +92 -0
- package/src/test/toros.test.ts +74 -20
- package/src/test/torosLimitOrder.test.ts +87 -42
- package/src/test/uniswap.test.ts +77 -128
- package/src/test/utils/testingHelper.ts +120 -0
- package/src/test/velodrome.test.ts +126 -92
- package/src/test/velodromeCL.test.ts +43 -31
- package/src/test/velodromeV2.test.ts +153 -95
- package/src/types.ts +22 -6
- package/src/utils/contract.ts +20 -0
- package/dist/services/futures/constants.d.ts +0 -1
- package/dist/services/futures/index.d.ts +0 -2
- package/dist/services/futures/margin.d.ts +0 -2
- package/dist/services/futures/trade.d.ts +0 -3
- package/dist/services/ramses/vesting.d.ts +0 -4
- package/dist/services/uniswap/V3Trade.d.ts +0 -3
- package/dist/test/utils/futures.d.ts +0 -2
- package/src/abi/IRamsesNonfungiblePositionManager.json +0 -486
- package/src/abi/ISynthetiXFuturesMarketV2.json +0 -531
- package/src/abi/ISynthetix.json +0 -139
- package/src/abi/IUniswapV3Quoter.json +0 -195
- package/src/abi/IUniswapV3Router.json +0 -221
- package/src/abi/IXRam.json +0 -99
- package/src/services/futures/constants.ts +0 -1
- package/src/services/futures/index.ts +0 -2
- package/src/services/futures/margin.ts +0 -10
- package/src/services/futures/trade.ts +0 -32
- package/src/services/ramses/vesting.ts +0 -24
- package/src/services/uniswap/V3Trade.ts +0 -46
- package/src/test/futures.test.ts +0 -51
- package/src/test/hyperliquid.test.ts +0 -107
- package/src/test/ramses.test.ts +0 -190
- package/src/test/ramsesCL.test.ts +0 -155
- package/src/test/synthetix.test.ts +0 -36
- package/src/test/utils/futures.ts +0 -14
package/README.md
CHANGED
|
@@ -13,18 +13,39 @@
|
|
|
13
13
|
|
|
14
14
|
## Installation
|
|
15
15
|
|
|
16
|
-
### Node
|
|
17
|
-
|
|
18
16
|
```bash
|
|
17
|
+
# npm
|
|
19
18
|
npm install @dhedge/v2-sdk
|
|
19
|
+
|
|
20
|
+
# yarn
|
|
21
|
+
yarn add @dhedge/v2-sdk
|
|
20
22
|
```
|
|
21
23
|
|
|
22
|
-
|
|
24
|
+
## Quick Start
|
|
23
25
|
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
+
```ts
|
|
27
|
+
import { Dhedge, Dapp, Network, ethers } from "@dhedge/v2-sdk";
|
|
28
|
+
|
|
29
|
+
// 1. Connect a wallet
|
|
30
|
+
const provider = new ethers.providers.JsonRpcProvider("YOUR_RPC_URL");
|
|
31
|
+
const wallet = new ethers.Wallet("YOUR_PRIVATE_KEY", provider);
|
|
32
|
+
const dhedge = new Dhedge(wallet, Network.POLYGON);
|
|
33
|
+
|
|
34
|
+
// 2. Load an existing vault and check its composition
|
|
35
|
+
const vault = await dhedge.loadPool("VAULT_ADDRESS");
|
|
36
|
+
const composition = await vault.getComposition();
|
|
37
|
+
|
|
38
|
+
// 3. Deposit USDC into the vault
|
|
39
|
+
await vault.approveDeposit("USDC_ADDRESS", ethers.constants.MaxUint256);
|
|
40
|
+
await vault.deposit("USDC_ADDRESS", "1000000"); // 1 USDC (6 decimals)
|
|
41
|
+
|
|
42
|
+
// 4. Trade USDC → WETH on KyberSwap (no API key needed)
|
|
43
|
+
await vault.approve(Dapp.KYBERSWAP, "USDC_ADDRESS", ethers.constants.MaxUint256);
|
|
44
|
+
await vault.trade(Dapp.KYBERSWAP, "USDC_ADDRESS", "WETH_ADDRESS", "1000000", 0.5);
|
|
26
45
|
```
|
|
27
46
|
|
|
47
|
+
> For aggregator-backed trades (1Inch, Odos), you'll need API keys — see [Initial Setup](#initial-setup).
|
|
48
|
+
|
|
28
49
|
## Usage
|
|
29
50
|
|
|
30
51
|
### Table of Contents
|
|
@@ -32,6 +53,14 @@ yarn add @dhedge/v2-sdk
|
|
|
32
53
|
<ol>
|
|
33
54
|
<li>
|
|
34
55
|
<a href="#initial-setup">Initial setup</a>
|
|
56
|
+
<ul>
|
|
57
|
+
<li><a href="#supported-networks">Supported networks</a></li>
|
|
58
|
+
<li><a href="#looking-up-addresses">Looking up addresses</a></li>
|
|
59
|
+
<li><a href="#common-revert-reasons">Common revert reasons</a></li>
|
|
60
|
+
<li><a href="#reference-tests-as-live-examples">Reference: tests as live examples</a></li>
|
|
61
|
+
<li><a href="#execution-model">Execution model</a></li>
|
|
62
|
+
<li><a href="#simulation-and-tx-data">Simulation and tx data</a></li>
|
|
63
|
+
</ul>
|
|
35
64
|
</li>
|
|
36
65
|
<li>
|
|
37
66
|
<a href="#general-vault-management">General Vault Management</a>
|
|
@@ -44,8 +73,11 @@ yarn add @dhedge/v2-sdk
|
|
|
44
73
|
<li><a href="#6-approve-asset-for-deposit">Approve asset for deposit</a></li>
|
|
45
74
|
<li><a href="#7-deposit-asset-into-a-vault">Deposit asset into a vault</a></li>
|
|
46
75
|
<li><a href="#8-withdraw-from-a-vault">Withdraw from a vault</a></li>
|
|
47
|
-
<li><a href="#9-approve-vault-asset-for-trading--staking
|
|
76
|
+
<li><a href="#9-approve-vault-asset-for-trading--staking">Approve vault asset for trading & staking</a></li>
|
|
48
77
|
<li><a href="#10-trade-vault-assets">Trade vault assets</a></li>
|
|
78
|
+
<li><a href="#toros-mint-flow">Toros mint flow</a></li>
|
|
79
|
+
<li><a href="#toros-redeem-flow">Toros redeem flow</a></li>
|
|
80
|
+
<li><a href="#toros-limit-orders">Toros limit orders</a></li>
|
|
49
81
|
</ul>
|
|
50
82
|
</li>
|
|
51
83
|
<li>
|
|
@@ -61,13 +93,28 @@ yarn add @dhedge/v2-sdk
|
|
|
61
93
|
<a href="#uniswap-v3-style">Uniswap-v3 style protocols</a>
|
|
62
94
|
</li>
|
|
63
95
|
<li>
|
|
64
|
-
<a href="#
|
|
96
|
+
<a href="#velodromecl--aerodromecl--pancakecl">VelodromeCL / AerodromeCL / PancakeCL</a>
|
|
97
|
+
</li>
|
|
98
|
+
<li>
|
|
99
|
+
<a href="#velodromev2--aerodrome">VelodromeV2 / Aerodrome</a>
|
|
100
|
+
</li>
|
|
101
|
+
<li>
|
|
102
|
+
<a href="#pendle">Pendle</a>
|
|
65
103
|
</li>
|
|
66
104
|
</ul>
|
|
67
105
|
</li>
|
|
68
106
|
<li>
|
|
69
107
|
<a href="#lendingborrowing-aave">Lending/Borrowing Aave</a>
|
|
70
108
|
</li>
|
|
109
|
+
<li>
|
|
110
|
+
<a href="#lending-compoundv3--fluid">Lending CompoundV3 / Fluid</a>
|
|
111
|
+
</li>
|
|
112
|
+
<li>
|
|
113
|
+
<a href="#the-flat-money-protocol">The Flat Money Protocol</a>
|
|
114
|
+
</li>
|
|
115
|
+
<li>
|
|
116
|
+
<a href="#development">Development</a>
|
|
117
|
+
</li>
|
|
71
118
|
|
|
72
119
|
</ol>
|
|
73
120
|
|
|
@@ -77,21 +124,24 @@ yarn add @dhedge/v2-sdk
|
|
|
77
124
|
|
|
78
125
|
---
|
|
79
126
|
|
|
80
|
-
If you want to use aggregators such as 1Inch or Odos, copy `.env.example` to `.env` and configure the API keys you need.
|
|
127
|
+
If you want to use aggregators such as 1Inch or Odos, or Ondo GM token swaps, copy `.env.example` to `.env` and configure the API keys you need.
|
|
81
128
|
|
|
82
129
|
```
|
|
83
130
|
ONEINCH_API_KEY=YOUR_API_KEY_FROM_1INCH
|
|
84
131
|
ODOS_API_KEY=YOUR_ODOS_API_KEY
|
|
132
|
+
ONDO_API_KEY=YOUR_ONDO_API_KEY
|
|
85
133
|
```
|
|
86
134
|
|
|
87
135
|
- `ONEINCH_API_KEY` is required for `Dapp.ONEINCH`
|
|
88
136
|
- `ODOS_API_KEY` is required for `Dapp.ODOS`
|
|
89
137
|
- `ODOS_API_KEY` can also be required by `completeTorosWithdrawal(...)` when a Toros withdrawal needs Odos-backed swap data
|
|
138
|
+
- `ONDO_API_KEY` is required for Ondo GM token swaps (`Dapp.ONDO`)
|
|
90
139
|
|
|
91
140
|
To get started:
|
|
92
141
|
|
|
93
142
|
- get a 1inch API key from the [1inch Developer Portal](https://docs.1inch.io/docs/aggregation-protocol/introduction)
|
|
94
143
|
- get an Odos API key via the [Odos developer docs](https://docs.odos.xyz/build/api-docs), and make sure it is valid for the Odos endpoint configured by this SDK
|
|
144
|
+
- get an Ondo API key by contacting [onboarding@ondo.finance](mailto:onboarding@ondo.finance)
|
|
95
145
|
- place the keys in a `.env` file at the project root before calling aggregator-backed methods
|
|
96
146
|
- if a required key is missing, the SDK will fail before transaction submission
|
|
97
147
|
|
|
@@ -118,6 +168,53 @@ Important notes:
|
|
|
118
168
|
- `loadPool(address)` assumes the address is a dHEDGE pool and resolves the manager contract automatically.
|
|
119
169
|
- `loadPool(address, false)` can be used when you want to work with a non-dHEDGE contract that should execute directly from the signer.
|
|
120
170
|
|
|
171
|
+
#### Supported networks
|
|
172
|
+
|
|
173
|
+
The SDK supports six networks: **Polygon**, **Optimism**, **Arbitrum**, **Base**, **Ethereum**, **Hyperliquid**. The most broadly-deployed protocols across these networks are **1inch**, **KyberSwap**, **Aave V3**, **Toros**, and **Toros LimitOrder**. The authoritative per-(network, Dapp) registry is `routerAddress` in `src/config.ts` — a Dapp is supported on a network iff `routerAddress[network][dapp]` is set. CL position managers, gauges, FlatMoney, and limit orders use parallel maps in the same file (`nonfungiblePositionManagerAddress`, `stakingAddress`, `flatMoneyContractAddresses`, `limitOrderAddress`).
|
|
174
|
+
|
|
175
|
+
#### Looking up addresses
|
|
176
|
+
|
|
177
|
+
Most code examples use placeholders like `"USDC_TOKEN_ADDRESS"`, `MARKET_ADDRESS`, or `BALANCER_LP_TOKEN_ADDRESS`. The single source of truth for what's deployed and whitelisted on each network is the **dHEDGE [V2-Public config directory](https://github.com/dhedge/V2-Public/tree/master/config)**.
|
|
178
|
+
|
|
179
|
+
What each file gives you:
|
|
180
|
+
|
|
181
|
+
- **`dHEDGE Assets list.json`** — every registered asset/contract: `assetName`, `assetAddress`, `assetType`, oracle config. Filter by `assetName` (e.g. `WBTC`, `USDC Native`, `Toros BTCBULL3X`, `cWETHv3`, `Fluid USDC`, `PT-wstETH-25JUN2026`) to get its address.
|
|
182
|
+
- **`dHEDGE Governance Contract Guards.csv`** — **active** contract guards: which protocols vaults are currently allowed to call (Aave, Pendle, Velodrome routers, Toros LimitOrderManager, etc.).
|
|
183
|
+
- **`dHEDGE Deprecated Contract Guards.csv`** — **deprecated** contract guards: protocols that used to be allowed but no longer are. Useful when a previously-working address starts reverting.
|
|
184
|
+
- **`dHEDGE Governance Asset Guards.csv`** — per-asset-type rules (which asset types vaults can hold).
|
|
185
|
+
|
|
186
|
+
Per-network direct links (raw URLs are agent-friendly — fetch them directly):
|
|
187
|
+
|
|
188
|
+
| Network | Folder | Assets | Active guards | Deprecated | Asset guards |
|
|
189
|
+
| --- | --- | --- | --- | --- | --- |
|
|
190
|
+
| Polygon | [folder](https://github.com/dhedge/V2-Public/tree/master/config/polygonProd) | [json](https://raw.githubusercontent.com/dhedge/V2-Public/master/config/polygonProd/dHEDGE%20Assets%20list%20-%20Polygon.json) | [csv](https://raw.githubusercontent.com/dhedge/V2-Public/master/config/polygonProd/dHEDGE%20Governance%20Contract%20Guards%20-%20Polygon.csv) | [csv](https://raw.githubusercontent.com/dhedge/V2-Public/master/config/polygonProd/dHEDGE%20Deprecated%20Contract%20Guards%20-%20Polygon.csv) | [csv](https://raw.githubusercontent.com/dhedge/V2-Public/master/config/polygonProd/dHEDGE%20Governance%20Asset%20Guards%20-%20Polygon.csv) |
|
|
191
|
+
| Optimism | [folder](https://github.com/dhedge/V2-Public/tree/master/config/ovm) | [json](https://raw.githubusercontent.com/dhedge/V2-Public/master/config/ovm/dHEDGE%20Assets%20list.json) | [csv](https://raw.githubusercontent.com/dhedge/V2-Public/master/config/ovm/dHEDGE%20Governance%20Contract%20Guards.csv) | [csv](https://raw.githubusercontent.com/dhedge/V2-Public/master/config/ovm/dHEDGE%20Deprecated%20Contract%20Guards.csv) | [csv](https://raw.githubusercontent.com/dhedge/V2-Public/master/config/ovm/dHEDGE%20Governance%20Asset%20Guards.csv) |
|
|
192
|
+
| Arbitrum | [folder](https://github.com/dhedge/V2-Public/tree/master/config/arbitrum) | [json](https://raw.githubusercontent.com/dhedge/V2-Public/master/config/arbitrum/dHEDGE%20Assets%20list.json) | [csv](https://raw.githubusercontent.com/dhedge/V2-Public/master/config/arbitrum/dHEDGE%20Governance%20Contract%20Guards.csv) | [csv](https://raw.githubusercontent.com/dhedge/V2-Public/master/config/arbitrum/dHEDGE%20Deprecated%20Contract%20Guards.csv) | [csv](https://raw.githubusercontent.com/dhedge/V2-Public/master/config/arbitrum/dHEDGE%20Governance%20Asset%20Guards.csv) |
|
|
193
|
+
| Base | [folder](https://github.com/dhedge/V2-Public/tree/master/config/base) | [json](https://raw.githubusercontent.com/dhedge/V2-Public/master/config/base/dHEDGE%20Assets%20list.json) | [csv](https://raw.githubusercontent.com/dhedge/V2-Public/master/config/base/dHEDGE%20Governance%20Contract%20Guards.csv) | [csv](https://raw.githubusercontent.com/dhedge/V2-Public/master/config/base/dHEDGE%20Deprecated%20Contract%20Guards.csv) | [csv](https://raw.githubusercontent.com/dhedge/V2-Public/master/config/base/dHEDGE%20Governance%20Asset%20Guards.csv) |
|
|
194
|
+
| Ethereum | [folder](https://github.com/dhedge/V2-Public/tree/master/config/ethereum) | [json](https://raw.githubusercontent.com/dhedge/V2-Public/master/config/ethereum/dHEDGE%20Assets%20list.json) | [csv](https://raw.githubusercontent.com/dhedge/V2-Public/master/config/ethereum/dHEDGE%20Governance%20Contract%20Guards.csv) | [csv](https://raw.githubusercontent.com/dhedge/V2-Public/master/config/ethereum/dHEDGE%20Deprecated%20Contract%20Guards.csv) | [csv](https://raw.githubusercontent.com/dhedge/V2-Public/master/config/ethereum/dHEDGE%20Governance%20Asset%20Guards.csv) |
|
|
195
|
+
| Hyperliquid | [folder](https://github.com/dhedge/V2-Public/tree/master/config/hyperevm) | [json](https://raw.githubusercontent.com/dhedge/V2-Public/master/config/hyperevm/dHEDGE%20Assets%20list.json) | [csv](https://raw.githubusercontent.com/dhedge/V2-Public/master/config/hyperevm/dHEDGE%20Governance%20Contract%20Guards.csv) | n/a | [csv](https://raw.githubusercontent.com/dhedge/V2-Public/master/config/hyperevm/dHEDGE%20Governance%20Asset%20Guards.csv) |
|
|
196
|
+
|
|
197
|
+
Router addresses (for `pool.approve(dapp, ...)`) live in `src/config.ts` → `routerAddress[network][dapp]`.
|
|
198
|
+
|
|
199
|
+
#### Common revert reasons
|
|
200
|
+
|
|
201
|
+
Two canonical references in [dhedge/V2-Public](https://github.com/dhedge/V2-Public/tree/master/readmes/errorCodes):
|
|
202
|
+
|
|
203
|
+
- [`dHEDGEV2ErrorCodes.json`](https://raw.githubusercontent.com/dhedge/V2-Public/master/readmes/errorCodes/dHEDGEV2ErrorCodes.json) — every `dhN` string thrown by dHEDGE contracts (e.g. `dh22`, `dh4`), with a description and recommended action. Fetch the JSON and look up `result["dh22"]`.
|
|
204
|
+
- [`4byteErrorCodes.md`](https://raw.githubusercontent.com/dhedge/V2-Public/master/readmes/errorCodes/4byteErrorCodes.md) — protocol-specific 4-byte custom-error selectors (DYTM, etc.) mapped to their source contracts.
|
|
205
|
+
|
|
206
|
+
For 4-byte selectors not in the file above, decode them with `cast 4byte 0x<selector>` (Foundry).
|
|
207
|
+
|
|
208
|
+
#### Reference: tests as live examples
|
|
209
|
+
|
|
210
|
+
Each protocol section below has a matching test under `src/test/`. The tests are the most up-to-date reference for the SDK's **call patterns** — they show the actual sequence of SDK methods (approve → trade, addLiquidity → stake, etc.) for each integration.
|
|
211
|
+
|
|
212
|
+
When reading a test as a reference, focus on the SDK calls themselves and ignore the test-only scaffolding (manager impersonation, asset funding via `setUSDCAmount` / `setTokenAmount`, oracle staleness fixes, fork RPC plumbing) — those exist because tests run against a Hardhat fork. A real vault manager calling the SDK from production code already _is_ the manager, holds the assets, and uses live RPC, so the only transferable part is the SDK invocation sequence.
|
|
213
|
+
|
|
214
|
+
Naming convention:
|
|
215
|
+
- `src/test/<protocol>.test.ts` — runs against a Hardhat fork.
|
|
216
|
+
- `src/test/<protocol>.onchain.test.ts` — requires a live RPC (used when a fork can't reproduce the path: CowSwap solver settlement, Hyperliquid CoreWriter, Toros `completeWithdrawal` aggregator quotes).
|
|
217
|
+
|
|
121
218
|
#### Execution model
|
|
122
219
|
|
|
123
220
|
By default, manager actions are executed through `pool.poolLogic.execTransaction(...)`.
|
|
@@ -129,8 +226,8 @@ const tx = await pool.trade(
|
|
|
129
226
|
Dapp.ONEINCH,
|
|
130
227
|
"USDC_TOKEN_ADDRESS",
|
|
131
228
|
"WETH_TOKEN_ADDRESS",
|
|
132
|
-
"1000000",
|
|
133
|
-
0.5,
|
|
229
|
+
"1000000", // 1 USDC (6 decimals)
|
|
230
|
+
0.5, // slippage %
|
|
134
231
|
null,
|
|
135
232
|
{
|
|
136
233
|
estimateGas: true,
|
|
@@ -141,19 +238,22 @@ const tx = await pool.trade(
|
|
|
141
238
|
|
|
142
239
|
#### Simulation and tx data
|
|
143
240
|
|
|
144
|
-
Most manager methods accept `sdkOptions` as the last argument.
|
|
241
|
+
Most manager methods accept `sdkOptions` as the last argument. The return shape depends on which flag you set:
|
|
242
|
+
|
|
243
|
+
- **No flag (default)** — sends the transaction and returns the underlying ethers `ContractTransaction` / `TransactionResponse`.
|
|
244
|
+
- **`true`** — shorthand for `{ estimateGas: true }`.
|
|
245
|
+
- **`{ estimateGas: true }`** — simulates and returns `{ gas, gasEstimationError, to, txData, minAmountOut }`. `gas` is `null` when `gasEstimationError` is set.
|
|
246
|
+
- **`{ onlyGetTxData: true }`** — returns `{ to, txData, minAmountOut }` (no `gas` / `gasEstimationError`) without sending or simulating.
|
|
145
247
|
|
|
146
|
-
|
|
147
|
-
- `{ estimateGas: true }` returns `{ gas, gasEstimationError, to, txData, minAmountOut }`
|
|
148
|
-
- `{ onlyGetTxData: true }` returns `{ to, txData, minAmountOut }` without sending a transaction
|
|
248
|
+
> `minAmountOut` is only populated by `pool.trade(...)` for the swap aggregators that fetch a quote from an external API: `Dapp.ONEINCH`, `Dapp.ODOS`, `Dapp.KYBERSWAP`, and `Dapp.PENDLE`. For all other Dapps and for non-trade methods (`approve`, `lend`, `addLiquidity*`, etc.) it is `null` — either the slippage limit is encoded inside the calldata at execution time, or the operation has no concept of a min-out. `Dapp.COWSWAP` rejects `estimateGas` and `onlyGetTxData` entirely.
|
|
149
249
|
|
|
150
250
|
```ts
|
|
151
251
|
const result = await pool.trade(
|
|
152
252
|
Dapp.ONEINCH,
|
|
153
253
|
"USDC_TOKEN_ADDRESS",
|
|
154
254
|
"WETH_TOKEN_ADDRESS",
|
|
155
|
-
"1000000",
|
|
156
|
-
0.5,
|
|
255
|
+
"1000000", // 1 USDC (6 decimals)
|
|
256
|
+
0.5, // slippage %
|
|
157
257
|
null,
|
|
158
258
|
{ estimateGas: true }
|
|
159
259
|
)
|
|
@@ -260,7 +360,7 @@ const tx = await vault.approveDeposit("USDC_TOKEN_ADDRESS", ethers.constants.Max
|
|
|
260
360
|
Deposit 1 USDC into a vault
|
|
261
361
|
|
|
262
362
|
```ts
|
|
263
|
-
const usdcDepositAmount = "
|
|
363
|
+
const usdcDepositAmount = "1000000" // 1 USDC (6 decimals)
|
|
264
364
|
const tx = await vault.deposit("USDC_TOKEN_ADDRESS", usdcDepositAmount);
|
|
265
365
|
```
|
|
266
366
|
|
|
@@ -277,11 +377,11 @@ const tx = await vault.withdraw(poolTokensWithdrawAmount);
|
|
|
277
377
|
|
|
278
378
|
Before the vault can trade or stake an asset on an external protocol, the vault must approve that protocol router or staking contract.
|
|
279
379
|
|
|
280
|
-
Approve unlimited amount of USDC to trade on
|
|
380
|
+
Approve unlimited amount of USDC to trade on KyberSwap
|
|
281
381
|
|
|
282
382
|
```ts
|
|
283
383
|
const tx = await vault.approve(
|
|
284
|
-
Dapp.
|
|
384
|
+
Dapp.KYBERSWAP,
|
|
285
385
|
"USDC_TOKEN_ADDRESS",
|
|
286
386
|
ethers.constants.MaxInt256
|
|
287
387
|
)
|
|
@@ -289,20 +389,23 @@ const tx = await vault.approve(
|
|
|
289
389
|
|
|
290
390
|
Approval model summary:
|
|
291
391
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
392
|
+
| Method | From → To | Spender resolution | When to use |
|
|
393
|
+
| --- | --- | --- | --- |
|
|
394
|
+
| `approveDeposit(asset, amount)` | user wallet → vault | the vault itself | Before `vault.deposit(asset, amount)` |
|
|
395
|
+
| `approve(dapp, asset, amount)` | vault → protocol router | `routerAddress[network][dapp]` | Before `vault.trade`, `vault.lend`, `vault.borrow`, etc. |
|
|
396
|
+
| `approveStaking(dapp, asset, amount)` | vault → staking contract | `stakingAddress[network][dapp]` | Before `vault.stake(dapp, ...)` (V2-style farms) |
|
|
397
|
+
| `approveSpender(spender, asset, amount)` | vault → arbitrary spender | caller-supplied | Custom integrations, CL position managers, etc. |
|
|
398
|
+
| `approveSpenderNFT(spender, nftContract, tokenId)` | vault → arbitrary spender (ERC-721) | caller-supplied | Approving a single CL position NFT before `stakeInGauge` |
|
|
296
399
|
|
|
297
400
|
#### 10. Trade vault assets
|
|
298
401
|
|
|
299
|
-
Trade 1 USDC into DAI on
|
|
402
|
+
Trade 1 USDC into DAI on KyberSwap. Other `Dapp` values supported by `vault.trade(...)` depend on the network — they include `TOROS`, `BALANCER`, `ONEINCH` (requires `ONEINCH_API_KEY`), `ODOS` (requires `ODOS_API_KEY`), `PENDLE`, and `COWSWAP`.
|
|
300
403
|
|
|
301
404
|
```ts
|
|
302
|
-
const amountIn = "1000000"
|
|
405
|
+
const amountIn = "1000000" // 1 USDC (6 decimals)
|
|
303
406
|
const slippage = 0.5
|
|
304
407
|
const tx = await vault.trade(
|
|
305
|
-
Dapp.
|
|
408
|
+
Dapp.KYBERSWAP,
|
|
306
409
|
"USDC_TOKEN_ADDRESS",
|
|
307
410
|
"DAI_TOKEN_ADDRESS",
|
|
308
411
|
amountIn,
|
|
@@ -310,6 +413,28 @@ const tx = await vault.trade(
|
|
|
310
413
|
)
|
|
311
414
|
```
|
|
312
415
|
|
|
416
|
+
**CowSwap** behaves differently from the other aggregators:
|
|
417
|
+
|
|
418
|
+
- Approve the **CoW Vault Relayer** (`0xC92E8bdf79f0507f65a392b0ab4667716BFE0110`) via `approveSpender`, not via `approve(Dapp.COWSWAP, ...)`.
|
|
419
|
+
- A single `vault.trade(Dapp.COWSWAP, ...)` call internally sends **two transactions** (submit the signed order, then `setPreSignature` on GPv2Settlement). The order is filled off-chain by solvers.
|
|
420
|
+
- `estimateGas` and `onlyGetTxData` are not supported.
|
|
421
|
+
|
|
422
|
+
```ts
|
|
423
|
+
await vault.approveSpender(
|
|
424
|
+
"0xC92E8bdf79f0507f65a392b0ab4667716BFE0110", // CoW Vault Relayer
|
|
425
|
+
"USDC_TOKEN_ADDRESS",
|
|
426
|
+
ethers.constants.MaxUint256
|
|
427
|
+
);
|
|
428
|
+
|
|
429
|
+
await vault.trade(
|
|
430
|
+
Dapp.COWSWAP,
|
|
431
|
+
"USDC_TOKEN_ADDRESS",
|
|
432
|
+
"WETH_TOKEN_ADDRESS",
|
|
433
|
+
"2000000",
|
|
434
|
+
0.5
|
|
435
|
+
);
|
|
436
|
+
```
|
|
437
|
+
|
|
313
438
|
#### Toros mint flow
|
|
314
439
|
|
|
315
440
|
Minting a Toros token uses `vault.trade(...)`, but it is not a generic token-to-token swap. The input asset must be a valid deposit asset for the underlying Toros vault.
|
|
@@ -325,7 +450,7 @@ const tx = await vault.trade(
|
|
|
325
450
|
Dapp.TOROS,
|
|
326
451
|
"USDC_TOKEN_ADDRESS",
|
|
327
452
|
"TOROS_TOKEN_ADDRESS",
|
|
328
|
-
"100000000",
|
|
453
|
+
"100000000", // 100 USDC (6 decimals)
|
|
329
454
|
slippage
|
|
330
455
|
)
|
|
331
456
|
```
|
|
@@ -357,7 +482,7 @@ const tx = await vault.trade(
|
|
|
357
482
|
Dapp.TOROS,
|
|
358
483
|
"TOROS_TOKEN_ADDRESS",
|
|
359
484
|
"USDC_TOKEN_ADDRESS",
|
|
360
|
-
"100000000",
|
|
485
|
+
"100000000", // amount of Toros vault tokens to redeem (Toros tokens are 18 decimals)
|
|
361
486
|
slippage
|
|
362
487
|
)
|
|
363
488
|
```
|
|
@@ -371,19 +496,69 @@ const tx = await vault.completeTorosWithdrawal(
|
|
|
371
496
|
)
|
|
372
497
|
```
|
|
373
498
|
|
|
499
|
+
#### Toros limit orders
|
|
500
|
+
|
|
501
|
+
Toros vaults support stop-loss / take-profit orders managed by the on-chain `PoolLimitOrderManager`. From a dHEDGE vault, the manager (or trader) can register an order against a held Toros vault token; once the pricing-asset price crosses one of the thresholds the order becomes executable.
|
|
502
|
+
|
|
503
|
+
A vault may hold at most one active limit order per Toros vault token. Prices are passed in 18-decimal fixed point (D18). Pass `null`/`undefined` to disable a side — stop-loss defaults to `0` (off) and take-profit defaults to `MaxUint256` (off).
|
|
504
|
+
|
|
505
|
+
The `pricingAsset` must match the address of an asset registered in the dHEDGE asset handler. Pick the entry in `dHEDGE Assets list.json` whose `assetName` represents the Toros vault's price reference (e.g. `WBTC` for BTC vaults, `WETH` for ETH vaults) and use its `assetAddress`. See [Looking up addresses](#looking-up-addresses) for the per-network URLs.
|
|
506
|
+
|
|
507
|
+
1. Approve the Toros vault token for the limit-order manager (one-time)
|
|
508
|
+
|
|
509
|
+
```ts
|
|
510
|
+
import { ethers } from "ethers";
|
|
511
|
+
|
|
512
|
+
await vault.approveTorosLimitOrder(
|
|
513
|
+
"TOROS_VAULT_ADDRESS",
|
|
514
|
+
ethers.constants.MaxUint256
|
|
515
|
+
);
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
2. Create an order — stop-loss at \$50,000 and take-profit at \$100,000 priced in WBTC
|
|
519
|
+
|
|
520
|
+
```ts
|
|
521
|
+
await vault.createTorosLimitOrder(
|
|
522
|
+
"TOROS_VAULT_ADDRESS",
|
|
523
|
+
ethers.utils.parseEther("0.001"), // amount of vault tokens (18 decimals)
|
|
524
|
+
ethers.utils.parseEther("50000"), // stopLossPriceD18
|
|
525
|
+
ethers.utils.parseEther("100000"), // takeProfitPriceD18
|
|
526
|
+
"WBTC_TOKEN_ADDRESS" // pricingAsset (assetAddress from dHEDGE Assets list.json)
|
|
527
|
+
);
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
3. Read the active order, modify it, or delete it
|
|
531
|
+
|
|
532
|
+
```ts
|
|
533
|
+
const order = await vault.getTorosLimitOrder(vault.address, "TOROS_VAULT_ADDRESS");
|
|
534
|
+
const exists = await vault.hasActiveTorosLimitOrder(vault.address, "TOROS_VAULT_ADDRESS");
|
|
535
|
+
|
|
536
|
+
await vault.modifyTorosLimitOrder(
|
|
537
|
+
"TOROS_VAULT_ADDRESS",
|
|
538
|
+
order.amount,
|
|
539
|
+
order.stopLossPriceD18.mul(95).div(100), // tighten stop by 5%
|
|
540
|
+
order.takeProfitPriceD18,
|
|
541
|
+
order.pricingAsset
|
|
542
|
+
);
|
|
543
|
+
|
|
544
|
+
await vault.deleteTorosLimitOrder("TOROS_VAULT_ADDRESS");
|
|
545
|
+
```
|
|
546
|
+
|
|
374
547
|
### Liquidity
|
|
375
548
|
|
|
376
549
|
---
|
|
377
550
|
|
|
378
551
|
#### Uniswap-v2 style
|
|
379
552
|
|
|
553
|
+
> **Note:** This path is **legacy**. Sushiswap is the only V2-style DEX still configured (Polygon only) and is not actively used; new integrations should prefer KyberSwap / 1inch / Pendle / Velodrome. The methods below remain for backwards compatibility.
|
|
554
|
+
|
|
380
555
|
For Uniswap-v2 like protocols, such as sushiswap, we use `addLiquidity`, `removeLiquidity`, `stake`, and `unstake`, and `harvestRewards`
|
|
381
556
|
|
|
382
557
|
1. Add USDC/DAI into a Sushiswap liquidity pool
|
|
383
558
|
|
|
384
559
|
```ts
|
|
385
|
-
const amountUsdc = "1000000"
|
|
386
|
-
const amountDai = "
|
|
560
|
+
const amountUsdc = "1000000" // 1 USDC (6 decimals)
|
|
561
|
+
const amountDai = "997085000000000000" // ~0.997 DAI (18 decimals)
|
|
387
562
|
const tx = await pool.addLiquidity(
|
|
388
563
|
Dapp.SUSHISWAP,
|
|
389
564
|
"USDC_TOKEN_ADDRESS",
|
|
@@ -396,7 +571,7 @@ const tx = await pool.addLiquidity(
|
|
|
396
571
|
2. Remove USDC/DAI worth of 1 Sushiswap LP from the liquidity pool
|
|
397
572
|
|
|
398
573
|
```ts
|
|
399
|
-
const amountSlpUsdcDai = "1000000000000000000"
|
|
574
|
+
const amountSlpUsdcDai = "1000000000000000000" // 1 LP token (18 decimals)
|
|
400
575
|
const tx = await pool.removeLiquidity(
|
|
401
576
|
Dapp.SUSHISWAP,
|
|
402
577
|
"USDC_TOKEN_ADDRESS",
|
|
@@ -405,7 +580,7 @@ const tx = await pool.removeLiquidity(
|
|
|
405
580
|
)
|
|
406
581
|
```
|
|
407
582
|
|
|
408
|
-
3. Approve unlimited
|
|
583
|
+
3. Approve unlimited amount of SLP USDC-DAI token for staking on Sushiswap
|
|
409
584
|
|
|
410
585
|
```ts
|
|
411
586
|
const tx = await pool.approveStaking(
|
|
@@ -418,7 +593,7 @@ const tx = await pool.approveStaking(
|
|
|
418
593
|
4. Stake 1 Sushiswap LP USDC/DAI token
|
|
419
594
|
|
|
420
595
|
```ts
|
|
421
|
-
const amountSlpUsdcDai = "1000000000000000000"
|
|
596
|
+
const amountSlpUsdcDai = "1000000000000000000" // 1 LP token (18 decimals)
|
|
422
597
|
const tx = await pool.stake(
|
|
423
598
|
Dapp.SUSHISWAP,
|
|
424
599
|
"SLP_USDC_DAI_TOKEN_ADDRESS",
|
|
@@ -429,7 +604,7 @@ const tx = await pool.stake(
|
|
|
429
604
|
5. Unstake 1 Sushiswap LP USDC/DAI token
|
|
430
605
|
|
|
431
606
|
```ts
|
|
432
|
-
const amountSlpUsdcDai = "1000000000000000000"
|
|
607
|
+
const amountSlpUsdcDai = "1000000000000000000" // 1 LP token (18 decimals)
|
|
433
608
|
const tx = await pool.unstake(
|
|
434
609
|
Dapp.SUSHISWAP,
|
|
435
610
|
"SLP_USDC_DAI_TOKEN_ADDRESS",
|
|
@@ -455,7 +630,11 @@ For Balancer, we use `joinBalancerPool`, `exitBalancerPool`, and `harvestBalance
|
|
|
455
630
|
```ts
|
|
456
631
|
const balancerPoolId = "0x03cd191f589d12b0582a99808cf19851e468e6b500010000000000000000000a"
|
|
457
632
|
const assets = [WBTC_TOKEN_ADDRESS, USDC_TOKEN_ADDRESS, WETH_TOKEN_ADDRESS];
|
|
458
|
-
const amounts = [
|
|
633
|
+
const amounts = [
|
|
634
|
+
"2000", // 0.00002 WBTC (8 decimals)
|
|
635
|
+
"1000000", // 1 USDC (6 decimals)
|
|
636
|
+
"200000000000000" // 0.0002 WETH (18 decimals)
|
|
637
|
+
];
|
|
459
638
|
const tx = await pool.joinBalancerPool(balancerPoolId, assets, amounts)
|
|
460
639
|
```
|
|
461
640
|
|
|
@@ -493,14 +672,15 @@ await pool.approveUniswapV3Liquidity(
|
|
|
493
672
|
ethers.constants.MaxInt256
|
|
494
673
|
);
|
|
495
674
|
const tx = await pool.addLiquidityUniswapV3(
|
|
496
|
-
|
|
675
|
+
Dapp.UNISWAPV3,
|
|
676
|
+
WETH_ADDRESS,
|
|
497
677
|
USDC_ADDRESS,
|
|
498
678
|
'430000000000000', // wethBalance
|
|
499
|
-
'100000000',
|
|
500
|
-
2000,
|
|
501
|
-
3000,
|
|
502
|
-
null,
|
|
503
|
-
null,
|
|
679
|
+
'100000000', // usdcBalance
|
|
680
|
+
2000, // minPrice
|
|
681
|
+
3000, // maxPrice
|
|
682
|
+
null, // minTick (use null when providing prices)
|
|
683
|
+
null, // maxTick (use null when providing prices)
|
|
504
684
|
FeeAmount.MEDIUM,
|
|
505
685
|
)
|
|
506
686
|
```
|
|
@@ -512,12 +692,11 @@ tokenId = await nonfungiblePositionManager.tokenOfOwnerByIndex(pool.address,0).t
|
|
|
512
692
|
const tx = await pool.decreaseLiquidity(
|
|
513
693
|
Dapp.UNISWAPV3,
|
|
514
694
|
tokenId,
|
|
515
|
-
50 //
|
|
695
|
+
50 // percent
|
|
516
696
|
);
|
|
517
697
|
```
|
|
518
698
|
|
|
519
699
|
Removing 100% will burn the NFT position.
|
|
520
|
-
Burning a Ramses CL NFT position won't claim rewards, so `getRewards` needs to be called before.
|
|
521
700
|
|
|
522
701
|
3. Increase liquidity in the existing WETH/USDC pool
|
|
523
702
|
|
|
@@ -536,22 +715,54 @@ const result = await pool.increaseLiquidity(
|
|
|
536
715
|
const tx = await pool.claimFees(Dapp.UNISWAPV3, tokenId);
|
|
537
716
|
```
|
|
538
717
|
|
|
539
|
-
|
|
718
|
+
#### VelodromeCL / AerodromeCL / PancakeCL
|
|
719
|
+
|
|
720
|
+
Velodrome CL, Aerodrome CL, and Pancake CL use the same SDK methods as Uniswap V3 — `approveUniswapV3Liquidity`, `addLiquidityUniswapV3`, `increaseLiquidity`, `decreaseLiquidity`, `claimFees` — just pass the matching `Dapp` enum (`Dapp.VELODROMECL`, `Dapp.AERODROMECL`, or `Dapp.PANCAKECL`). Use `minTick` / `maxTick` (not `minPrice` / `maxPrice`) and pass the pool's tick spacing as the last argument instead of a Uniswap fee tier.
|
|
721
|
+
|
|
722
|
+
1. Mint a position (USDC/WETH on Aerodrome CL)
|
|
723
|
+
|
|
724
|
+
```ts
|
|
725
|
+
await pool.approveSpender(AERODROME_POSITION_MANAGER, USDC_ADDRESS, ethers.constants.MaxUint256);
|
|
726
|
+
await pool.approveSpender(AERODROME_POSITION_MANAGER, WETH_ADDRESS, ethers.constants.MaxUint256);
|
|
727
|
+
|
|
728
|
+
await pool.addLiquidityUniswapV3(
|
|
729
|
+
Dapp.AERODROMECL,
|
|
730
|
+
USDC_ADDRESS,
|
|
731
|
+
WETH_ADDRESS,
|
|
732
|
+
usdcAmount,
|
|
733
|
+
wethAmount,
|
|
734
|
+
null, // minPrice (use ticks instead)
|
|
735
|
+
null, // maxPrice
|
|
736
|
+
-2, // minTick
|
|
737
|
+
4, // maxTick
|
|
738
|
+
1 // tick spacing
|
|
739
|
+
);
|
|
740
|
+
```
|
|
741
|
+
|
|
742
|
+
`AERODROME_POSITION_MANAGER` is the chain's CL `nonfungiblePositionManager`; look it up via `nonfungiblePositionManagerAddress[network][Dapp.AERODROMECL]` from `src/config.ts`.
|
|
743
|
+
|
|
744
|
+
2. Stake the CL position in a gauge (then unstake later)
|
|
540
745
|
|
|
541
746
|
```ts
|
|
542
|
-
|
|
747
|
+
await pool.approveSpenderNFT(GAUGE_ADDRESS, AERODROME_POSITION_MANAGER, tokenId);
|
|
748
|
+
await pool.stakeInGauge(Dapp.AERODROMECL, GAUGE_ADDRESS, tokenId);
|
|
749
|
+
|
|
750
|
+
// later
|
|
751
|
+
await pool.unstakeFromGauge(GAUGE_ADDRESS, tokenId);
|
|
543
752
|
```
|
|
544
753
|
|
|
545
|
-
|
|
754
|
+
`claimFees(Dapp.AERODROMECL, tokenId)` collects swap fees on an unstaked position and gauge rewards (e.g. AERO/VELO) on a staked position.
|
|
755
|
+
|
|
756
|
+
#### VelodromeV2 / Aerodrome
|
|
546
757
|
|
|
547
|
-
For VelodromeV2 /
|
|
758
|
+
For VelodromeV2 / Aerodrome, we use `addLiquidityV2`, `stakeInGauge`, `unstakeFromGauge`, `removeLiquidityV2`, and `claimFees`.
|
|
548
759
|
|
|
549
|
-
Add liquidity of 100 USDC and 0.00043 WETH to USDC/WETH
|
|
550
|
-
(for Velodrome
|
|
760
|
+
Add liquidity of 100 USDC and 0.00043 WETH to a USDC/WETH pool
|
|
761
|
+
(for Velodrome use `Dapp.VELODROMEV2`, for Aerodrome use `Dapp.AERODROME`). See examples in the [velodromeV2 test](https://github.com/dhedge/dhedge-v2-sdk/blob/master/src/test/velodromeV2.test.ts) and [aerodrome test](https://github.com/dhedge/dhedge-v2-sdk/blob/master/src/test/aerodrome.test.ts).
|
|
551
762
|
|
|
552
763
|
```ts
|
|
553
764
|
const tx = await pool.addLiquidityV2(
|
|
554
|
-
Dapp.
|
|
765
|
+
Dapp.VELODROMEV2,
|
|
555
766
|
USDC_ADDRESS,
|
|
556
767
|
WETH_ADDRESS,
|
|
557
768
|
'10000000',
|
|
@@ -560,6 +771,56 @@ const tx = await pool.addLiquidityV2(
|
|
|
560
771
|
)
|
|
561
772
|
```
|
|
562
773
|
|
|
774
|
+
#### Pendle
|
|
775
|
+
|
|
776
|
+
For Pendle Principal Tokens (PT), we use `pool.trade(Dapp.PENDLE, ...)` to swap an underlying token into a PT, swap a PT back into its underlying, or — once the market has expired — redeem a PT to its underlying via the SY exchange rate. The SDK auto-detects expired markets via the Pendle API and routes the call through the matured-exit path.
|
|
777
|
+
|
|
778
|
+
> **Note:** Only a limited set of PTs is supported. Each PT (and its underlying / SY) must be whitelisted in the dHEDGE asset handler before a vault can hold or trade it. Check the live asset registry (see [Looking up addresses](#looking-up-addresses)) for the current list — attempts to trade an unwhitelisted PT will revert.
|
|
779
|
+
|
|
780
|
+
1. Swap underlying (e.g. wstETH) into a PT in an active market
|
|
781
|
+
|
|
782
|
+
```ts
|
|
783
|
+
const wstEthBalance = await vault.utils.getBalance(WSTETH_ADDRESS, vault.address);
|
|
784
|
+
await vault.approve(Dapp.PENDLE, WSTETH_ADDRESS, ethers.constants.MaxUint256);
|
|
785
|
+
await vault.trade(
|
|
786
|
+
Dapp.PENDLE,
|
|
787
|
+
WSTETH_ADDRESS,
|
|
788
|
+
PT_WSTETH_ADDRESS,
|
|
789
|
+
wstEthBalance,
|
|
790
|
+
1 // slippage %
|
|
791
|
+
);
|
|
792
|
+
```
|
|
793
|
+
|
|
794
|
+
2. Swap a PT back into its underlying before maturity
|
|
795
|
+
|
|
796
|
+
```ts
|
|
797
|
+
const ptBalance = await vault.utils.getBalance(PT_WSTETH_ADDRESS, vault.address);
|
|
798
|
+
await vault.approve(Dapp.PENDLE, PT_WSTETH_ADDRESS, ethers.constants.MaxUint256);
|
|
799
|
+
await vault.trade(
|
|
800
|
+
Dapp.PENDLE,
|
|
801
|
+
PT_WSTETH_ADDRESS,
|
|
802
|
+
WSTETH_ADDRESS,
|
|
803
|
+
ptBalance,
|
|
804
|
+
1
|
|
805
|
+
);
|
|
806
|
+
```
|
|
807
|
+
|
|
808
|
+
3. Redeem a matured PT to its underlying
|
|
809
|
+
|
|
810
|
+
After the market's `expiry`, the SDK detects the inactive market and uses the `exitPostExpToToken` path; the amount received is `ptAmount * 1e18 / SY.exchangeRate()`.
|
|
811
|
+
|
|
812
|
+
```ts
|
|
813
|
+
const ptBalance = await vault.utils.getBalance(MATURED_PT_ADDRESS, vault.address);
|
|
814
|
+
await vault.approve(Dapp.PENDLE, MATURED_PT_ADDRESS, ethers.constants.MaxUint256);
|
|
815
|
+
await vault.trade(
|
|
816
|
+
Dapp.PENDLE,
|
|
817
|
+
MATURED_PT_ADDRESS,
|
|
818
|
+
UNDERLYING_ADDRESS,
|
|
819
|
+
ptBalance,
|
|
820
|
+
1
|
|
821
|
+
);
|
|
822
|
+
```
|
|
823
|
+
|
|
563
824
|
<br>
|
|
564
825
|
|
|
565
826
|
### Lending/Borrowing Aave
|
|
@@ -571,25 +832,61 @@ For Aave, we use `lend`, `withdrawDeposit`, `borrow` and `repay`
|
|
|
571
832
|
##### 1. Deposit 1 USDC into Aave lending pool
|
|
572
833
|
|
|
573
834
|
```ts
|
|
574
|
-
const tx = await pool.lend(Dapp.AAVE, USDC_TOKEN_ADDRESS, "1000000")
|
|
835
|
+
const tx = await pool.lend(Dapp.AAVE, USDC_TOKEN_ADDRESS, "1000000") // 1 USDC (6 decimals)
|
|
575
836
|
```
|
|
576
837
|
|
|
577
838
|
##### 2. Withdraw 1 USDC from Aave lending pool
|
|
578
839
|
|
|
579
840
|
```ts
|
|
580
|
-
const tx = await pool.withdrawDeposit(Dapp.AAVE, USDC_TOKEN_ADDRESS, "1000000")
|
|
841
|
+
const tx = await pool.withdrawDeposit(Dapp.AAVE, USDC_TOKEN_ADDRESS, "1000000") // 1 USDC (6 decimals)
|
|
581
842
|
```
|
|
582
843
|
|
|
583
844
|
##### 3. Borrow 0.0001 WETH from Aave lending pool
|
|
584
845
|
|
|
585
846
|
```ts
|
|
586
|
-
const tx = await pool.borrow(Dapp.AAVE, WETH_TOKEN_ADDRESS, "100000000000000");
|
|
847
|
+
const tx = await pool.borrow(Dapp.AAVE, WETH_TOKEN_ADDRESS, "100000000000000"); // 0.0001 WETH (18 decimals)
|
|
587
848
|
```
|
|
588
849
|
|
|
589
850
|
##### 4. Repay 0.0001 WETH to Aave lending pool
|
|
590
851
|
|
|
591
852
|
```ts
|
|
592
|
-
const tx = await pool.repay(Dapp.AAVE, WETH_TOKEN_ADDRESS, "100000000000000");
|
|
853
|
+
const tx = await pool.repay(Dapp.AAVE, WETH_TOKEN_ADDRESS, "100000000000000"); // 0.0001 WETH (18 decimals)
|
|
854
|
+
```
|
|
855
|
+
|
|
856
|
+
<br>
|
|
857
|
+
|
|
858
|
+
### Lending CompoundV3 / Fluid
|
|
859
|
+
|
|
860
|
+
CompoundV3 markets (cTokens, e.g. `cWETHv3`, `cUSDCv3`) and Fluid markets (fTokens, e.g. `fWETH`, `fUSDC`) share the same SDK surface — `lendCompoundV3` to supply and `withdrawCompoundV3` to withdraw, with the market address as the first argument. CompoundV3 additionally exposes `harvestCompoundV3Rewards` to claim COMP rewards (Fluid has no rewards harvest path).
|
|
861
|
+
|
|
862
|
+
Look up market addresses in `dHEDGE Assets list.json` (see [Looking up addresses](#looking-up-addresses)). Compound V3 markets are `assetType: "28"` with `contractGuard: "CompoundV3CometContractGuard"`; Fluid markets are `assetType: "34"` with `contractGuard: "FluidTokenContractGuard"`.
|
|
863
|
+
|
|
864
|
+
1. Approve the asset for the market
|
|
865
|
+
|
|
866
|
+
```ts
|
|
867
|
+
await pool.approveSpender(MARKET_ADDRESS, ASSET_ADDRESS, ethers.constants.MaxUint256);
|
|
868
|
+
```
|
|
869
|
+
|
|
870
|
+
2. Supply
|
|
871
|
+
|
|
872
|
+
```ts
|
|
873
|
+
// CompoundV3
|
|
874
|
+
await pool.lendCompoundV3(CWETH_V3_ADDRESS, WETH_ADDRESS, "1000000000000000000"); // 1 WETH (18 decimals)
|
|
875
|
+
|
|
876
|
+
// Fluid uses the same method, just a Fluid market address
|
|
877
|
+
await pool.lendCompoundV3(FWETH_ADDRESS, WETH_ADDRESS, "1000000000000000000");
|
|
878
|
+
```
|
|
879
|
+
|
|
880
|
+
3. Withdraw
|
|
881
|
+
|
|
882
|
+
```ts
|
|
883
|
+
await pool.withdrawCompoundV3(MARKET_ADDRESS, ASSET_ADDRESS, AMOUNT);
|
|
884
|
+
```
|
|
885
|
+
|
|
886
|
+
4. (CompoundV3 only) Harvest COMP rewards
|
|
887
|
+
|
|
888
|
+
```ts
|
|
889
|
+
await pool.harvestCompoundV3Rewards(CWETH_V3_ADDRESS);
|
|
593
890
|
```
|
|
594
891
|
|
|
595
892
|
<br>
|
|
@@ -625,3 +922,56 @@ const tx = await pool.repay(Dapp.AAVE, WETH_TOKEN_ADDRESS, "100000000000000");
|
|
|
625
922
|
```ts
|
|
626
923
|
await pool.cancelOrderViaFlatMoney();
|
|
627
924
|
```
|
|
925
|
+
|
|
926
|
+
<br>
|
|
927
|
+
|
|
928
|
+
## Development
|
|
929
|
+
|
|
930
|
+
### Setup
|
|
931
|
+
|
|
932
|
+
```sh
|
|
933
|
+
# install
|
|
934
|
+
yarn install
|
|
935
|
+
|
|
936
|
+
# copy and edit env
|
|
937
|
+
cp .env.example .env
|
|
938
|
+
```
|
|
939
|
+
|
|
940
|
+
`.env` recognised keys:
|
|
941
|
+
|
|
942
|
+
| Variable | Purpose |
|
|
943
|
+
| --- | --- |
|
|
944
|
+
| `PRIVATE_KEY` | Wallet used by tests; needs to be the manager (or trader) of `TEST_POOL[network]` for fork tests. |
|
|
945
|
+
| `<NETWORK>_URL` | RPC URL used to fork or run on-chain tests. One per network: `POLYGON_URL`, `OPTIMISM_URL`, `ARBITRUM_URL`, `BASE_URL`, `ETHEREUM_URL`, `PLASMA_URL`, `HYPERLIQUID_URL`. |
|
|
946
|
+
| `ONEINCH_API_KEY` | Required only for `Dapp.ONEINCH` calls. |
|
|
947
|
+
|
|
948
|
+
### Build & lint
|
|
949
|
+
|
|
950
|
+
```sh
|
|
951
|
+
yarn build # tsdx build
|
|
952
|
+
yarn lint # tsdx lint
|
|
953
|
+
```
|
|
954
|
+
|
|
955
|
+
### Fork a network
|
|
956
|
+
|
|
957
|
+
Each fork command spins up a local Hardhat node on a fixed port (the test wallet helper looks these ports up automatically when `onFork: true`):
|
|
958
|
+
|
|
959
|
+
| Network | Command | Local port |
|
|
960
|
+
| --- | --- | :---: |
|
|
961
|
+
| Polygon | `yarn fork:polygon` | 8542 |
|
|
962
|
+
| Optimism | `yarn fork:optimism` | 8544 |
|
|
963
|
+
| Arbitrum | `yarn fork:arbitrum` | 8540 |
|
|
964
|
+
| Base | `yarn fork:base` | 8546 |
|
|
965
|
+
| Ethereum | `yarn fork:ethereum` | 8547 |
|
|
966
|
+
| Plasma | `yarn fork:plasma` | 8548 |
|
|
967
|
+
| Hyperliquid | `yarn fork:hyperliquid` | 8549 |
|
|
968
|
+
|
|
969
|
+
### Run tests
|
|
970
|
+
|
|
971
|
+
```sh
|
|
972
|
+
yarn test # run everything
|
|
973
|
+
npx jest src/test/aave.test.ts # one file
|
|
974
|
+
npx jest -t "trades USDC into WETH" # by test name
|
|
975
|
+
```
|
|
976
|
+
|
|
977
|
+
Most test files declare a network with `testingHelper({ network: Network.X, testingRun, onFork: true })`. The helper picks `http://127.0.0.1:<port>` when `onFork: true` (the matching `yarn fork:<network>` must be running) and `process.env.<NETWORK>_URL` when `onFork: false` — used for "on-chain" tests like `*.onchain.test.ts` that can't run on a fork (e.g. CowSwap solver settlement, Hyperliquid CoreWriter, Toros completeWithdrawal aggregator quotes).
|