@dhedge/v2-sdk 2.1.8 → 2.2.0
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 +400 -53
- 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/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 +19 -4
- package/dist/utils/contract.d.ts +20 -0
- package/dist/v2-sdk.cjs.development.js +4996 -6742
- 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 +5001 -6742
- 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/config.ts +13 -8
- package/src/entities/pool.ts +46 -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/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/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 +20 -5
- 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
|
|
|
@@ -118,6 +165,53 @@ Important notes:
|
|
|
118
165
|
- `loadPool(address)` assumes the address is a dHEDGE pool and resolves the manager contract automatically.
|
|
119
166
|
- `loadPool(address, false)` can be used when you want to work with a non-dHEDGE contract that should execute directly from the signer.
|
|
120
167
|
|
|
168
|
+
#### Supported networks
|
|
169
|
+
|
|
170
|
+
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`).
|
|
171
|
+
|
|
172
|
+
#### Looking up addresses
|
|
173
|
+
|
|
174
|
+
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)**.
|
|
175
|
+
|
|
176
|
+
What each file gives you:
|
|
177
|
+
|
|
178
|
+
- **`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.
|
|
179
|
+
- **`dHEDGE Governance Contract Guards.csv`** — **active** contract guards: which protocols vaults are currently allowed to call (Aave, Pendle, Velodrome routers, Toros LimitOrderManager, etc.).
|
|
180
|
+
- **`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.
|
|
181
|
+
- **`dHEDGE Governance Asset Guards.csv`** — per-asset-type rules (which asset types vaults can hold).
|
|
182
|
+
|
|
183
|
+
Per-network direct links (raw URLs are agent-friendly — fetch them directly):
|
|
184
|
+
|
|
185
|
+
| Network | Folder | Assets | Active guards | Deprecated | Asset guards |
|
|
186
|
+
| --- | --- | --- | --- | --- | --- |
|
|
187
|
+
| 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) |
|
|
188
|
+
| 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) |
|
|
189
|
+
| 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) |
|
|
190
|
+
| 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) |
|
|
191
|
+
| 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) |
|
|
192
|
+
| 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) |
|
|
193
|
+
|
|
194
|
+
Router addresses (for `pool.approve(dapp, ...)`) live in `src/config.ts` → `routerAddress[network][dapp]`.
|
|
195
|
+
|
|
196
|
+
#### Common revert reasons
|
|
197
|
+
|
|
198
|
+
Two canonical references in [dhedge/V2-Public](https://github.com/dhedge/V2-Public/tree/master/readmes/errorCodes):
|
|
199
|
+
|
|
200
|
+
- [`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"]`.
|
|
201
|
+
- [`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.
|
|
202
|
+
|
|
203
|
+
For 4-byte selectors not in the file above, decode them with `cast 4byte 0x<selector>` (Foundry).
|
|
204
|
+
|
|
205
|
+
#### Reference: tests as live examples
|
|
206
|
+
|
|
207
|
+
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.
|
|
208
|
+
|
|
209
|
+
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.
|
|
210
|
+
|
|
211
|
+
Naming convention:
|
|
212
|
+
- `src/test/<protocol>.test.ts` — runs against a Hardhat fork.
|
|
213
|
+
- `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).
|
|
214
|
+
|
|
121
215
|
#### Execution model
|
|
122
216
|
|
|
123
217
|
By default, manager actions are executed through `pool.poolLogic.execTransaction(...)`.
|
|
@@ -129,8 +223,8 @@ const tx = await pool.trade(
|
|
|
129
223
|
Dapp.ONEINCH,
|
|
130
224
|
"USDC_TOKEN_ADDRESS",
|
|
131
225
|
"WETH_TOKEN_ADDRESS",
|
|
132
|
-
"1000000",
|
|
133
|
-
0.5,
|
|
226
|
+
"1000000", // 1 USDC (6 decimals)
|
|
227
|
+
0.5, // slippage %
|
|
134
228
|
null,
|
|
135
229
|
{
|
|
136
230
|
estimateGas: true,
|
|
@@ -141,19 +235,22 @@ const tx = await pool.trade(
|
|
|
141
235
|
|
|
142
236
|
#### Simulation and tx data
|
|
143
237
|
|
|
144
|
-
Most manager methods accept `sdkOptions` as the last argument.
|
|
238
|
+
Most manager methods accept `sdkOptions` as the last argument. The return shape depends on which flag you set:
|
|
239
|
+
|
|
240
|
+
- **No flag (default)** — sends the transaction and returns the underlying ethers `ContractTransaction` / `TransactionResponse`.
|
|
241
|
+
- **`true`** — shorthand for `{ estimateGas: true }`.
|
|
242
|
+
- **`{ estimateGas: true }`** — simulates and returns `{ gas, gasEstimationError, to, txData, minAmountOut }`. `gas` is `null` when `gasEstimationError` is set.
|
|
243
|
+
- **`{ onlyGetTxData: true }`** — returns `{ to, txData, minAmountOut }` (no `gas` / `gasEstimationError`) without sending or simulating.
|
|
145
244
|
|
|
146
|
-
|
|
147
|
-
- `{ estimateGas: true }` returns `{ gas, gasEstimationError, to, txData, minAmountOut }`
|
|
148
|
-
- `{ onlyGetTxData: true }` returns `{ to, txData, minAmountOut }` without sending a transaction
|
|
245
|
+
> `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
246
|
|
|
150
247
|
```ts
|
|
151
248
|
const result = await pool.trade(
|
|
152
249
|
Dapp.ONEINCH,
|
|
153
250
|
"USDC_TOKEN_ADDRESS",
|
|
154
251
|
"WETH_TOKEN_ADDRESS",
|
|
155
|
-
"1000000",
|
|
156
|
-
0.5,
|
|
252
|
+
"1000000", // 1 USDC (6 decimals)
|
|
253
|
+
0.5, // slippage %
|
|
157
254
|
null,
|
|
158
255
|
{ estimateGas: true }
|
|
159
256
|
)
|
|
@@ -260,7 +357,7 @@ const tx = await vault.approveDeposit("USDC_TOKEN_ADDRESS", ethers.constants.Max
|
|
|
260
357
|
Deposit 1 USDC into a vault
|
|
261
358
|
|
|
262
359
|
```ts
|
|
263
|
-
const usdcDepositAmount = "
|
|
360
|
+
const usdcDepositAmount = "1000000" // 1 USDC (6 decimals)
|
|
264
361
|
const tx = await vault.deposit("USDC_TOKEN_ADDRESS", usdcDepositAmount);
|
|
265
362
|
```
|
|
266
363
|
|
|
@@ -277,11 +374,11 @@ const tx = await vault.withdraw(poolTokensWithdrawAmount);
|
|
|
277
374
|
|
|
278
375
|
Before the vault can trade or stake an asset on an external protocol, the vault must approve that protocol router or staking contract.
|
|
279
376
|
|
|
280
|
-
Approve unlimited amount of USDC to trade on
|
|
377
|
+
Approve unlimited amount of USDC to trade on KyberSwap
|
|
281
378
|
|
|
282
379
|
```ts
|
|
283
380
|
const tx = await vault.approve(
|
|
284
|
-
Dapp.
|
|
381
|
+
Dapp.KYBERSWAP,
|
|
285
382
|
"USDC_TOKEN_ADDRESS",
|
|
286
383
|
ethers.constants.MaxInt256
|
|
287
384
|
)
|
|
@@ -289,20 +386,23 @@ const tx = await vault.approve(
|
|
|
289
386
|
|
|
290
387
|
Approval model summary:
|
|
291
388
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
389
|
+
| Method | From → To | Spender resolution | When to use |
|
|
390
|
+
| --- | --- | --- | --- |
|
|
391
|
+
| `approveDeposit(asset, amount)` | user wallet → vault | the vault itself | Before `vault.deposit(asset, amount)` |
|
|
392
|
+
| `approve(dapp, asset, amount)` | vault → protocol router | `routerAddress[network][dapp]` | Before `vault.trade`, `vault.lend`, `vault.borrow`, etc. |
|
|
393
|
+
| `approveStaking(dapp, asset, amount)` | vault → staking contract | `stakingAddress[network][dapp]` | Before `vault.stake(dapp, ...)` (V2-style farms) |
|
|
394
|
+
| `approveSpender(spender, asset, amount)` | vault → arbitrary spender | caller-supplied | Custom integrations, CL position managers, etc. |
|
|
395
|
+
| `approveSpenderNFT(spender, nftContract, tokenId)` | vault → arbitrary spender (ERC-721) | caller-supplied | Approving a single CL position NFT before `stakeInGauge` |
|
|
296
396
|
|
|
297
397
|
#### 10. Trade vault assets
|
|
298
398
|
|
|
299
|
-
Trade 1 USDC into DAI on
|
|
399
|
+
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
400
|
|
|
301
401
|
```ts
|
|
302
|
-
const amountIn = "1000000"
|
|
402
|
+
const amountIn = "1000000" // 1 USDC (6 decimals)
|
|
303
403
|
const slippage = 0.5
|
|
304
404
|
const tx = await vault.trade(
|
|
305
|
-
Dapp.
|
|
405
|
+
Dapp.KYBERSWAP,
|
|
306
406
|
"USDC_TOKEN_ADDRESS",
|
|
307
407
|
"DAI_TOKEN_ADDRESS",
|
|
308
408
|
amountIn,
|
|
@@ -310,6 +410,28 @@ const tx = await vault.trade(
|
|
|
310
410
|
)
|
|
311
411
|
```
|
|
312
412
|
|
|
413
|
+
**CowSwap** behaves differently from the other aggregators:
|
|
414
|
+
|
|
415
|
+
- Approve the **CoW Vault Relayer** (`0xC92E8bdf79f0507f65a392b0ab4667716BFE0110`) via `approveSpender`, not via `approve(Dapp.COWSWAP, ...)`.
|
|
416
|
+
- 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.
|
|
417
|
+
- `estimateGas` and `onlyGetTxData` are not supported.
|
|
418
|
+
|
|
419
|
+
```ts
|
|
420
|
+
await vault.approveSpender(
|
|
421
|
+
"0xC92E8bdf79f0507f65a392b0ab4667716BFE0110", // CoW Vault Relayer
|
|
422
|
+
"USDC_TOKEN_ADDRESS",
|
|
423
|
+
ethers.constants.MaxUint256
|
|
424
|
+
);
|
|
425
|
+
|
|
426
|
+
await vault.trade(
|
|
427
|
+
Dapp.COWSWAP,
|
|
428
|
+
"USDC_TOKEN_ADDRESS",
|
|
429
|
+
"WETH_TOKEN_ADDRESS",
|
|
430
|
+
"2000000",
|
|
431
|
+
0.5
|
|
432
|
+
);
|
|
433
|
+
```
|
|
434
|
+
|
|
313
435
|
#### Toros mint flow
|
|
314
436
|
|
|
315
437
|
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 +447,7 @@ const tx = await vault.trade(
|
|
|
325
447
|
Dapp.TOROS,
|
|
326
448
|
"USDC_TOKEN_ADDRESS",
|
|
327
449
|
"TOROS_TOKEN_ADDRESS",
|
|
328
|
-
"100000000",
|
|
450
|
+
"100000000", // 100 USDC (6 decimals)
|
|
329
451
|
slippage
|
|
330
452
|
)
|
|
331
453
|
```
|
|
@@ -357,7 +479,7 @@ const tx = await vault.trade(
|
|
|
357
479
|
Dapp.TOROS,
|
|
358
480
|
"TOROS_TOKEN_ADDRESS",
|
|
359
481
|
"USDC_TOKEN_ADDRESS",
|
|
360
|
-
"100000000",
|
|
482
|
+
"100000000", // amount of Toros vault tokens to redeem (Toros tokens are 18 decimals)
|
|
361
483
|
slippage
|
|
362
484
|
)
|
|
363
485
|
```
|
|
@@ -371,19 +493,69 @@ const tx = await vault.completeTorosWithdrawal(
|
|
|
371
493
|
)
|
|
372
494
|
```
|
|
373
495
|
|
|
496
|
+
#### Toros limit orders
|
|
497
|
+
|
|
498
|
+
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.
|
|
499
|
+
|
|
500
|
+
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).
|
|
501
|
+
|
|
502
|
+
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.
|
|
503
|
+
|
|
504
|
+
1. Approve the Toros vault token for the limit-order manager (one-time)
|
|
505
|
+
|
|
506
|
+
```ts
|
|
507
|
+
import { ethers } from "ethers";
|
|
508
|
+
|
|
509
|
+
await vault.approveTorosLimitOrder(
|
|
510
|
+
"TOROS_VAULT_ADDRESS",
|
|
511
|
+
ethers.constants.MaxUint256
|
|
512
|
+
);
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
2. Create an order — stop-loss at \$50,000 and take-profit at \$100,000 priced in WBTC
|
|
516
|
+
|
|
517
|
+
```ts
|
|
518
|
+
await vault.createTorosLimitOrder(
|
|
519
|
+
"TOROS_VAULT_ADDRESS",
|
|
520
|
+
ethers.utils.parseEther("0.001"), // amount of vault tokens (18 decimals)
|
|
521
|
+
ethers.utils.parseEther("50000"), // stopLossPriceD18
|
|
522
|
+
ethers.utils.parseEther("100000"), // takeProfitPriceD18
|
|
523
|
+
"WBTC_TOKEN_ADDRESS" // pricingAsset (assetAddress from dHEDGE Assets list.json)
|
|
524
|
+
);
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
3. Read the active order, modify it, or delete it
|
|
528
|
+
|
|
529
|
+
```ts
|
|
530
|
+
const order = await vault.getTorosLimitOrder(vault.address, "TOROS_VAULT_ADDRESS");
|
|
531
|
+
const exists = await vault.hasActiveTorosLimitOrder(vault.address, "TOROS_VAULT_ADDRESS");
|
|
532
|
+
|
|
533
|
+
await vault.modifyTorosLimitOrder(
|
|
534
|
+
"TOROS_VAULT_ADDRESS",
|
|
535
|
+
order.amount,
|
|
536
|
+
order.stopLossPriceD18.mul(95).div(100), // tighten stop by 5%
|
|
537
|
+
order.takeProfitPriceD18,
|
|
538
|
+
order.pricingAsset
|
|
539
|
+
);
|
|
540
|
+
|
|
541
|
+
await vault.deleteTorosLimitOrder("TOROS_VAULT_ADDRESS");
|
|
542
|
+
```
|
|
543
|
+
|
|
374
544
|
### Liquidity
|
|
375
545
|
|
|
376
546
|
---
|
|
377
547
|
|
|
378
548
|
#### Uniswap-v2 style
|
|
379
549
|
|
|
550
|
+
> **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.
|
|
551
|
+
|
|
380
552
|
For Uniswap-v2 like protocols, such as sushiswap, we use `addLiquidity`, `removeLiquidity`, `stake`, and `unstake`, and `harvestRewards`
|
|
381
553
|
|
|
382
554
|
1. Add USDC/DAI into a Sushiswap liquidity pool
|
|
383
555
|
|
|
384
556
|
```ts
|
|
385
|
-
const amountUsdc = "1000000"
|
|
386
|
-
const amountDai = "
|
|
557
|
+
const amountUsdc = "1000000" // 1 USDC (6 decimals)
|
|
558
|
+
const amountDai = "997085000000000000" // ~0.997 DAI (18 decimals)
|
|
387
559
|
const tx = await pool.addLiquidity(
|
|
388
560
|
Dapp.SUSHISWAP,
|
|
389
561
|
"USDC_TOKEN_ADDRESS",
|
|
@@ -396,7 +568,7 @@ const tx = await pool.addLiquidity(
|
|
|
396
568
|
2. Remove USDC/DAI worth of 1 Sushiswap LP from the liquidity pool
|
|
397
569
|
|
|
398
570
|
```ts
|
|
399
|
-
const amountSlpUsdcDai = "1000000000000000000"
|
|
571
|
+
const amountSlpUsdcDai = "1000000000000000000" // 1 LP token (18 decimals)
|
|
400
572
|
const tx = await pool.removeLiquidity(
|
|
401
573
|
Dapp.SUSHISWAP,
|
|
402
574
|
"USDC_TOKEN_ADDRESS",
|
|
@@ -405,7 +577,7 @@ const tx = await pool.removeLiquidity(
|
|
|
405
577
|
)
|
|
406
578
|
```
|
|
407
579
|
|
|
408
|
-
3. Approve unlimited
|
|
580
|
+
3. Approve unlimited amount of SLP USDC-DAI token for staking on Sushiswap
|
|
409
581
|
|
|
410
582
|
```ts
|
|
411
583
|
const tx = await pool.approveStaking(
|
|
@@ -418,7 +590,7 @@ const tx = await pool.approveStaking(
|
|
|
418
590
|
4. Stake 1 Sushiswap LP USDC/DAI token
|
|
419
591
|
|
|
420
592
|
```ts
|
|
421
|
-
const amountSlpUsdcDai = "1000000000000000000"
|
|
593
|
+
const amountSlpUsdcDai = "1000000000000000000" // 1 LP token (18 decimals)
|
|
422
594
|
const tx = await pool.stake(
|
|
423
595
|
Dapp.SUSHISWAP,
|
|
424
596
|
"SLP_USDC_DAI_TOKEN_ADDRESS",
|
|
@@ -429,7 +601,7 @@ const tx = await pool.stake(
|
|
|
429
601
|
5. Unstake 1 Sushiswap LP USDC/DAI token
|
|
430
602
|
|
|
431
603
|
```ts
|
|
432
|
-
const amountSlpUsdcDai = "1000000000000000000"
|
|
604
|
+
const amountSlpUsdcDai = "1000000000000000000" // 1 LP token (18 decimals)
|
|
433
605
|
const tx = await pool.unstake(
|
|
434
606
|
Dapp.SUSHISWAP,
|
|
435
607
|
"SLP_USDC_DAI_TOKEN_ADDRESS",
|
|
@@ -455,7 +627,11 @@ For Balancer, we use `joinBalancerPool`, `exitBalancerPool`, and `harvestBalance
|
|
|
455
627
|
```ts
|
|
456
628
|
const balancerPoolId = "0x03cd191f589d12b0582a99808cf19851e468e6b500010000000000000000000a"
|
|
457
629
|
const assets = [WBTC_TOKEN_ADDRESS, USDC_TOKEN_ADDRESS, WETH_TOKEN_ADDRESS];
|
|
458
|
-
const amounts = [
|
|
630
|
+
const amounts = [
|
|
631
|
+
"2000", // 0.00002 WBTC (8 decimals)
|
|
632
|
+
"1000000", // 1 USDC (6 decimals)
|
|
633
|
+
"200000000000000" // 0.0002 WETH (18 decimals)
|
|
634
|
+
];
|
|
459
635
|
const tx = await pool.joinBalancerPool(balancerPoolId, assets, amounts)
|
|
460
636
|
```
|
|
461
637
|
|
|
@@ -493,14 +669,15 @@ await pool.approveUniswapV3Liquidity(
|
|
|
493
669
|
ethers.constants.MaxInt256
|
|
494
670
|
);
|
|
495
671
|
const tx = await pool.addLiquidityUniswapV3(
|
|
496
|
-
|
|
672
|
+
Dapp.UNISWAPV3,
|
|
673
|
+
WETH_ADDRESS,
|
|
497
674
|
USDC_ADDRESS,
|
|
498
675
|
'430000000000000', // wethBalance
|
|
499
|
-
'100000000',
|
|
500
|
-
2000,
|
|
501
|
-
3000,
|
|
502
|
-
null,
|
|
503
|
-
null,
|
|
676
|
+
'100000000', // usdcBalance
|
|
677
|
+
2000, // minPrice
|
|
678
|
+
3000, // maxPrice
|
|
679
|
+
null, // minTick (use null when providing prices)
|
|
680
|
+
null, // maxTick (use null when providing prices)
|
|
504
681
|
FeeAmount.MEDIUM,
|
|
505
682
|
)
|
|
506
683
|
```
|
|
@@ -512,12 +689,11 @@ tokenId = await nonfungiblePositionManager.tokenOfOwnerByIndex(pool.address,0).t
|
|
|
512
689
|
const tx = await pool.decreaseLiquidity(
|
|
513
690
|
Dapp.UNISWAPV3,
|
|
514
691
|
tokenId,
|
|
515
|
-
50 //
|
|
692
|
+
50 // percent
|
|
516
693
|
);
|
|
517
694
|
```
|
|
518
695
|
|
|
519
696
|
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
697
|
|
|
522
698
|
3. Increase liquidity in the existing WETH/USDC pool
|
|
523
699
|
|
|
@@ -536,22 +712,54 @@ const result = await pool.increaseLiquidity(
|
|
|
536
712
|
const tx = await pool.claimFees(Dapp.UNISWAPV3, tokenId);
|
|
537
713
|
```
|
|
538
714
|
|
|
539
|
-
|
|
715
|
+
#### VelodromeCL / AerodromeCL / PancakeCL
|
|
716
|
+
|
|
717
|
+
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.
|
|
718
|
+
|
|
719
|
+
1. Mint a position (USDC/WETH on Aerodrome CL)
|
|
720
|
+
|
|
721
|
+
```ts
|
|
722
|
+
await pool.approveSpender(AERODROME_POSITION_MANAGER, USDC_ADDRESS, ethers.constants.MaxUint256);
|
|
723
|
+
await pool.approveSpender(AERODROME_POSITION_MANAGER, WETH_ADDRESS, ethers.constants.MaxUint256);
|
|
724
|
+
|
|
725
|
+
await pool.addLiquidityUniswapV3(
|
|
726
|
+
Dapp.AERODROMECL,
|
|
727
|
+
USDC_ADDRESS,
|
|
728
|
+
WETH_ADDRESS,
|
|
729
|
+
usdcAmount,
|
|
730
|
+
wethAmount,
|
|
731
|
+
null, // minPrice (use ticks instead)
|
|
732
|
+
null, // maxPrice
|
|
733
|
+
-2, // minTick
|
|
734
|
+
4, // maxTick
|
|
735
|
+
1 // tick spacing
|
|
736
|
+
);
|
|
737
|
+
```
|
|
738
|
+
|
|
739
|
+
`AERODROME_POSITION_MANAGER` is the chain's CL `nonfungiblePositionManager`; look it up via `nonfungiblePositionManagerAddress[network][Dapp.AERODROMECL]` from `src/config.ts`.
|
|
740
|
+
|
|
741
|
+
2. Stake the CL position in a gauge (then unstake later)
|
|
540
742
|
|
|
541
743
|
```ts
|
|
542
|
-
|
|
744
|
+
await pool.approveSpenderNFT(GAUGE_ADDRESS, AERODROME_POSITION_MANAGER, tokenId);
|
|
745
|
+
await pool.stakeInGauge(Dapp.AERODROMECL, GAUGE_ADDRESS, tokenId);
|
|
746
|
+
|
|
747
|
+
// later
|
|
748
|
+
await pool.unstakeFromGauge(GAUGE_ADDRESS, tokenId);
|
|
543
749
|
```
|
|
544
750
|
|
|
545
|
-
|
|
751
|
+
`claimFees(Dapp.AERODROMECL, tokenId)` collects swap fees on an unstaked position and gauge rewards (e.g. AERO/VELO) on a staked position.
|
|
752
|
+
|
|
753
|
+
#### VelodromeV2 / Aerodrome
|
|
546
754
|
|
|
547
|
-
For VelodromeV2 /
|
|
755
|
+
For VelodromeV2 / Aerodrome, we use `addLiquidityV2`, `stakeInGauge`, `unstakeFromGauge`, `removeLiquidityV2`, and `claimFees`.
|
|
548
756
|
|
|
549
|
-
Add liquidity of 100 USDC and 0.00043 WETH to USDC/WETH
|
|
550
|
-
(for Velodrome
|
|
757
|
+
Add liquidity of 100 USDC and 0.00043 WETH to a USDC/WETH pool
|
|
758
|
+
(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
759
|
|
|
552
760
|
```ts
|
|
553
761
|
const tx = await pool.addLiquidityV2(
|
|
554
|
-
Dapp.
|
|
762
|
+
Dapp.VELODROMEV2,
|
|
555
763
|
USDC_ADDRESS,
|
|
556
764
|
WETH_ADDRESS,
|
|
557
765
|
'10000000',
|
|
@@ -560,6 +768,56 @@ const tx = await pool.addLiquidityV2(
|
|
|
560
768
|
)
|
|
561
769
|
```
|
|
562
770
|
|
|
771
|
+
#### Pendle
|
|
772
|
+
|
|
773
|
+
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.
|
|
774
|
+
|
|
775
|
+
> **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.
|
|
776
|
+
|
|
777
|
+
1. Swap underlying (e.g. wstETH) into a PT in an active market
|
|
778
|
+
|
|
779
|
+
```ts
|
|
780
|
+
const wstEthBalance = await vault.utils.getBalance(WSTETH_ADDRESS, vault.address);
|
|
781
|
+
await vault.approve(Dapp.PENDLE, WSTETH_ADDRESS, ethers.constants.MaxUint256);
|
|
782
|
+
await vault.trade(
|
|
783
|
+
Dapp.PENDLE,
|
|
784
|
+
WSTETH_ADDRESS,
|
|
785
|
+
PT_WSTETH_ADDRESS,
|
|
786
|
+
wstEthBalance,
|
|
787
|
+
1 // slippage %
|
|
788
|
+
);
|
|
789
|
+
```
|
|
790
|
+
|
|
791
|
+
2. Swap a PT back into its underlying before maturity
|
|
792
|
+
|
|
793
|
+
```ts
|
|
794
|
+
const ptBalance = await vault.utils.getBalance(PT_WSTETH_ADDRESS, vault.address);
|
|
795
|
+
await vault.approve(Dapp.PENDLE, PT_WSTETH_ADDRESS, ethers.constants.MaxUint256);
|
|
796
|
+
await vault.trade(
|
|
797
|
+
Dapp.PENDLE,
|
|
798
|
+
PT_WSTETH_ADDRESS,
|
|
799
|
+
WSTETH_ADDRESS,
|
|
800
|
+
ptBalance,
|
|
801
|
+
1
|
|
802
|
+
);
|
|
803
|
+
```
|
|
804
|
+
|
|
805
|
+
3. Redeem a matured PT to its underlying
|
|
806
|
+
|
|
807
|
+
After the market's `expiry`, the SDK detects the inactive market and uses the `exitPostExpToToken` path; the amount received is `ptAmount * 1e18 / SY.exchangeRate()`.
|
|
808
|
+
|
|
809
|
+
```ts
|
|
810
|
+
const ptBalance = await vault.utils.getBalance(MATURED_PT_ADDRESS, vault.address);
|
|
811
|
+
await vault.approve(Dapp.PENDLE, MATURED_PT_ADDRESS, ethers.constants.MaxUint256);
|
|
812
|
+
await vault.trade(
|
|
813
|
+
Dapp.PENDLE,
|
|
814
|
+
MATURED_PT_ADDRESS,
|
|
815
|
+
UNDERLYING_ADDRESS,
|
|
816
|
+
ptBalance,
|
|
817
|
+
1
|
|
818
|
+
);
|
|
819
|
+
```
|
|
820
|
+
|
|
563
821
|
<br>
|
|
564
822
|
|
|
565
823
|
### Lending/Borrowing Aave
|
|
@@ -571,25 +829,61 @@ For Aave, we use `lend`, `withdrawDeposit`, `borrow` and `repay`
|
|
|
571
829
|
##### 1. Deposit 1 USDC into Aave lending pool
|
|
572
830
|
|
|
573
831
|
```ts
|
|
574
|
-
const tx = await pool.lend(Dapp.AAVE, USDC_TOKEN_ADDRESS, "1000000")
|
|
832
|
+
const tx = await pool.lend(Dapp.AAVE, USDC_TOKEN_ADDRESS, "1000000") // 1 USDC (6 decimals)
|
|
575
833
|
```
|
|
576
834
|
|
|
577
835
|
##### 2. Withdraw 1 USDC from Aave lending pool
|
|
578
836
|
|
|
579
837
|
```ts
|
|
580
|
-
const tx = await pool.withdrawDeposit(Dapp.AAVE, USDC_TOKEN_ADDRESS, "1000000")
|
|
838
|
+
const tx = await pool.withdrawDeposit(Dapp.AAVE, USDC_TOKEN_ADDRESS, "1000000") // 1 USDC (6 decimals)
|
|
581
839
|
```
|
|
582
840
|
|
|
583
841
|
##### 3. Borrow 0.0001 WETH from Aave lending pool
|
|
584
842
|
|
|
585
843
|
```ts
|
|
586
|
-
const tx = await pool.borrow(Dapp.AAVE, WETH_TOKEN_ADDRESS, "100000000000000");
|
|
844
|
+
const tx = await pool.borrow(Dapp.AAVE, WETH_TOKEN_ADDRESS, "100000000000000"); // 0.0001 WETH (18 decimals)
|
|
587
845
|
```
|
|
588
846
|
|
|
589
847
|
##### 4. Repay 0.0001 WETH to Aave lending pool
|
|
590
848
|
|
|
591
849
|
```ts
|
|
592
|
-
const tx = await pool.repay(Dapp.AAVE, WETH_TOKEN_ADDRESS, "100000000000000");
|
|
850
|
+
const tx = await pool.repay(Dapp.AAVE, WETH_TOKEN_ADDRESS, "100000000000000"); // 0.0001 WETH (18 decimals)
|
|
851
|
+
```
|
|
852
|
+
|
|
853
|
+
<br>
|
|
854
|
+
|
|
855
|
+
### Lending CompoundV3 / Fluid
|
|
856
|
+
|
|
857
|
+
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).
|
|
858
|
+
|
|
859
|
+
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"`.
|
|
860
|
+
|
|
861
|
+
1. Approve the asset for the market
|
|
862
|
+
|
|
863
|
+
```ts
|
|
864
|
+
await pool.approveSpender(MARKET_ADDRESS, ASSET_ADDRESS, ethers.constants.MaxUint256);
|
|
865
|
+
```
|
|
866
|
+
|
|
867
|
+
2. Supply
|
|
868
|
+
|
|
869
|
+
```ts
|
|
870
|
+
// CompoundV3
|
|
871
|
+
await pool.lendCompoundV3(CWETH_V3_ADDRESS, WETH_ADDRESS, "1000000000000000000"); // 1 WETH (18 decimals)
|
|
872
|
+
|
|
873
|
+
// Fluid uses the same method, just a Fluid market address
|
|
874
|
+
await pool.lendCompoundV3(FWETH_ADDRESS, WETH_ADDRESS, "1000000000000000000");
|
|
875
|
+
```
|
|
876
|
+
|
|
877
|
+
3. Withdraw
|
|
878
|
+
|
|
879
|
+
```ts
|
|
880
|
+
await pool.withdrawCompoundV3(MARKET_ADDRESS, ASSET_ADDRESS, AMOUNT);
|
|
881
|
+
```
|
|
882
|
+
|
|
883
|
+
4. (CompoundV3 only) Harvest COMP rewards
|
|
884
|
+
|
|
885
|
+
```ts
|
|
886
|
+
await pool.harvestCompoundV3Rewards(CWETH_V3_ADDRESS);
|
|
593
887
|
```
|
|
594
888
|
|
|
595
889
|
<br>
|
|
@@ -625,3 +919,56 @@ const tx = await pool.repay(Dapp.AAVE, WETH_TOKEN_ADDRESS, "100000000000000");
|
|
|
625
919
|
```ts
|
|
626
920
|
await pool.cancelOrderViaFlatMoney();
|
|
627
921
|
```
|
|
922
|
+
|
|
923
|
+
<br>
|
|
924
|
+
|
|
925
|
+
## Development
|
|
926
|
+
|
|
927
|
+
### Setup
|
|
928
|
+
|
|
929
|
+
```sh
|
|
930
|
+
# install
|
|
931
|
+
yarn install
|
|
932
|
+
|
|
933
|
+
# copy and edit env
|
|
934
|
+
cp .env.example .env
|
|
935
|
+
```
|
|
936
|
+
|
|
937
|
+
`.env` recognised keys:
|
|
938
|
+
|
|
939
|
+
| Variable | Purpose |
|
|
940
|
+
| --- | --- |
|
|
941
|
+
| `PRIVATE_KEY` | Wallet used by tests; needs to be the manager (or trader) of `TEST_POOL[network]` for fork tests. |
|
|
942
|
+
| `<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`. |
|
|
943
|
+
| `ONEINCH_API_KEY` | Required only for `Dapp.ONEINCH` calls. |
|
|
944
|
+
|
|
945
|
+
### Build & lint
|
|
946
|
+
|
|
947
|
+
```sh
|
|
948
|
+
yarn build # tsdx build
|
|
949
|
+
yarn lint # tsdx lint
|
|
950
|
+
```
|
|
951
|
+
|
|
952
|
+
### Fork a network
|
|
953
|
+
|
|
954
|
+
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`):
|
|
955
|
+
|
|
956
|
+
| Network | Command | Local port |
|
|
957
|
+
| --- | --- | :---: |
|
|
958
|
+
| Polygon | `yarn fork:polygon` | 8542 |
|
|
959
|
+
| Optimism | `yarn fork:optimism` | 8544 |
|
|
960
|
+
| Arbitrum | `yarn fork:arbitrum` | 8540 |
|
|
961
|
+
| Base | `yarn fork:base` | 8546 |
|
|
962
|
+
| Ethereum | `yarn fork:ethereum` | 8547 |
|
|
963
|
+
| Plasma | `yarn fork:plasma` | 8548 |
|
|
964
|
+
| Hyperliquid | `yarn fork:hyperliquid` | 8549 |
|
|
965
|
+
|
|
966
|
+
### Run tests
|
|
967
|
+
|
|
968
|
+
```sh
|
|
969
|
+
yarn test # run everything
|
|
970
|
+
npx jest src/test/aave.test.ts # one file
|
|
971
|
+
npx jest -t "trades USDC into WETH" # by test name
|
|
972
|
+
```
|
|
973
|
+
|
|
974
|
+
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).
|