curvance 4.0.4 → 4.1.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 +595 -59
- package/dist/chains/arb-sepolia.json +44 -0
- package/dist/chains/arbitrum.d.ts.map +1 -1
- package/dist/chains/arbitrum.js +4 -2
- package/dist/chains/arbitrum.js.map +1 -1
- package/dist/chains/index.d.ts +4 -0
- package/dist/chains/index.d.ts.map +1 -1
- package/dist/chains/index.js +15 -0
- package/dist/chains/index.js.map +1 -1
- package/dist/chains/monad-mainnet.json +26 -1
- package/dist/chains/monad.d.ts.map +1 -1
- package/dist/chains/monad.js +4 -2
- package/dist/chains/monad.js.map +1 -1
- package/dist/chains/rpc.d.ts +57 -0
- package/dist/chains/rpc.d.ts.map +1 -0
- package/dist/chains/rpc.js +47 -0
- package/dist/chains/rpc.js.map +1 -0
- package/dist/classes/Api.d.ts +4 -3
- package/dist/classes/Api.d.ts.map +1 -1
- package/dist/classes/Api.js +7 -7
- package/dist/classes/Api.js.map +1 -1
- package/dist/classes/BorrowableCToken.d.ts +3 -2
- package/dist/classes/BorrowableCToken.d.ts.map +1 -1
- package/dist/classes/BorrowableCToken.js +6 -5
- package/dist/classes/BorrowableCToken.js.map +1 -1
- package/dist/classes/CToken.d.ts +11 -3
- package/dist/classes/CToken.d.ts.map +1 -1
- package/dist/classes/CToken.js +85 -79
- package/dist/classes/CToken.js.map +1 -1
- package/dist/classes/Calldata.d.ts +2 -2
- package/dist/classes/Calldata.d.ts.map +1 -1
- package/dist/classes/Calldata.js +2 -2
- package/dist/classes/Calldata.js.map +1 -1
- package/dist/classes/DexAggregators/IDexAgg.d.ts +2 -2
- package/dist/classes/DexAggregators/IDexAgg.d.ts.map +1 -1
- package/dist/classes/DexAggregators/Kuru.d.ts +2 -2
- package/dist/classes/DexAggregators/Kuru.d.ts.map +1 -1
- package/dist/classes/DexAggregators/Kuru.js +3 -4
- package/dist/classes/DexAggregators/Kuru.js.map +1 -1
- package/dist/classes/DexAggregators/KuruMainnet.d.ts +1 -0
- package/dist/classes/DexAggregators/KuruMainnet.d.ts.map +1 -0
- package/dist/classes/DexAggregators/KuruMainnet.js +228 -0
- package/dist/classes/DexAggregators/KuruMainnet.js.map +1 -0
- package/dist/classes/DexAggregators/KyberSwap.d.ts +2 -2
- package/dist/classes/DexAggregators/KyberSwap.d.ts.map +1 -1
- package/dist/classes/DexAggregators/KyberSwap.js +10 -8
- package/dist/classes/DexAggregators/KyberSwap.js.map +1 -1
- package/dist/classes/DexAggregators/MultiDexAgg.d.ts +2 -2
- package/dist/classes/DexAggregators/MultiDexAgg.d.ts.map +1 -1
- package/dist/classes/DexAggregators/MultiDexAgg.js +3 -3
- package/dist/classes/DexAggregators/MultiDexAgg.js.map +1 -1
- package/dist/classes/ERC20.d.ts +5 -3
- package/dist/classes/ERC20.d.ts.map +1 -1
- package/dist/classes/ERC20.js +20 -14
- package/dist/classes/ERC20.js.map +1 -1
- package/dist/classes/ERC4626.d.ts.map +1 -1
- package/dist/classes/ERC4626.js +3 -1
- package/dist/classes/ERC4626.js.map +1 -1
- package/dist/classes/Kuru.d.ts +59 -0
- package/dist/classes/Kuru.d.ts.map +1 -0
- package/dist/classes/Kuru.js +167 -0
- package/dist/classes/Kuru.js.map +1 -0
- package/dist/classes/KuruMainnet.d.ts +59 -0
- package/dist/classes/KuruMainnet.d.ts.map +1 -0
- package/dist/classes/KuruMainnet.js +167 -0
- package/dist/classes/KuruMainnet.js.map +1 -0
- package/dist/classes/Market.d.ts +13 -4
- package/dist/classes/Market.d.ts.map +1 -1
- package/dist/classes/Market.js +86 -28
- package/dist/classes/Market.js.map +1 -1
- package/dist/classes/NativeToken.d.ts +6 -3
- package/dist/classes/NativeToken.d.ts.map +1 -1
- package/dist/classes/NativeToken.js +11 -16
- package/dist/classes/NativeToken.js.map +1 -1
- package/dist/classes/OptimizerReader.d.ts +3 -3
- package/dist/classes/OptimizerReader.d.ts.map +1 -1
- package/dist/classes/OptimizerReader.js +1 -1
- package/dist/classes/OptimizerReader.js.map +1 -1
- package/dist/classes/OracleManager.d.ts +3 -3
- package/dist/classes/OracleManager.d.ts.map +1 -1
- package/dist/classes/OracleManager.js +1 -1
- package/dist/classes/OracleManager.js.map +1 -1
- package/dist/classes/PositionManager.d.ts +2 -2
- package/dist/classes/PositionManager.d.ts.map +1 -1
- package/dist/classes/PositionManager.js +4 -4
- package/dist/classes/PositionManager.js.map +1 -1
- package/dist/classes/ProtocolReader.d.ts +18 -4
- package/dist/classes/ProtocolReader.d.ts.map +1 -1
- package/dist/classes/ProtocolReader.js +177 -55
- package/dist/classes/ProtocolReader.js.map +1 -1
- package/dist/classes/Redstone.d.ts.map +1 -1
- package/dist/classes/Redstone.js +1 -2
- package/dist/classes/Redstone.js.map +1 -1
- package/dist/classes/Zapper.d.ts +4 -2
- package/dist/classes/Zapper.d.ts.map +1 -1
- package/dist/classes/Zapper.js +14 -13
- package/dist/classes/Zapper.js.map +1 -1
- package/dist/classes/index.d.ts +1 -1
- package/dist/classes/index.d.ts.map +1 -1
- package/dist/classes/index.js +6 -1
- package/dist/classes/index.js.map +1 -1
- package/dist/contracts/monad-mainnet.json +1 -1
- package/dist/helpers.d.ts +3 -1
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +34 -4
- package/dist/helpers.js.map +1 -1
- package/dist/integrations/snapshot.d.ts.map +1 -1
- package/dist/integrations/snapshot.js +4 -18
- package/dist/integrations/snapshot.js.map +1 -1
- package/dist/retry-provider.d.ts +81 -6
- package/dist/retry-provider.d.ts.map +1 -1
- package/dist/retry-provider.js +489 -35
- package/dist/retry-provider.js.map +1 -1
- package/dist/setup.d.ts +14 -3
- package/dist/setup.d.ts.map +1 -1
- package/dist/setup.js +56 -20
- package/dist/setup.js.map +1 -1
- package/dist/snapshot.d.ts +53 -0
- package/dist/snapshot.d.ts.map +1 -0
- package/dist/snapshot.js +103 -0
- package/dist/snapshot.js.map +1 -0
- package/dist/types.d.ts +2 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -1,28 +1,8 @@
|
|
|
1
1
|
<p style="text-align: center;width:100%">
|
|
2
|
-
<img src="https://pbs.twimg.com/profile_banners/1445781144125857796/
|
|
2
|
+
<img src="https://pbs.twimg.com/profile_banners/1445781144125857796/1773687595/1500x500" alt="Curvance"/>
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
- **Efficient RPC Usage:** Preloads all market data with minimal calls.
|
|
7
|
-
- **Typed Contracts:** Uses ethers.js for safe, typed blockchain interactions.
|
|
8
|
-
- **Price Feeds:** Integrates Redstone for on-chain price updates.
|
|
9
|
-
- **Decimal Support:** Handles BigInt and floating-point math with decimal.js.
|
|
10
|
-
- **Flexible Providers:** Works with multiple providers:
|
|
11
|
-
- `ethers.Wallet` - For CLI/Local wallet connections
|
|
12
|
-
- `ethers.JsonRpcSigner` - For browser interactions
|
|
13
|
-
- `ethers.JsonRpcProvider` - For a user configured RPC
|
|
14
|
-
- `null` - We setup a JsonRpcProvider if we configured one for you
|
|
15
|
-
- **Property conversions:** For example getting a users asset balance can optionally be returned in USD or token amount
|
|
16
|
-
- **Contract addresses:** Use this package to pull in curvance contracts & have the latest contract addresses (especially useful on testnet)
|
|
17
|
-
|
|
18
|
-
Dependencies:
|
|
19
|
-
- [Redstone](https://www.npmjs.com/package/@redstone-finance/sdk): Used to attach price updates in a multicall for some actions.
|
|
20
|
-
- [Decimals](https://www.npmjs.com/package/decimal.js): Any floating point path being done with BigInt is done with Decimals.
|
|
21
|
-
- [ethers.js](https://www.npmjs.com/package/ethers): All signers passed into the protocol are using ether.js typed signers.
|
|
22
|
-
|
|
23
|
-
Notes:
|
|
24
|
-
- All values are returned in either BigInt or [Decimals](https://www.npmjs.com/package/decimal.js)
|
|
25
|
-
- We use [alchemy](https://dashboard.alchemy.com/apps) chain prefixing for exaple: `eth-mainnet` or `arb-sepolia` to represents chains
|
|
5
|
+
A TypeScript SDK for interacting with the Curvance protocol. Built on ethers v6 with a bulk-loaded cache model — `setupChain()` preloads all market data in 1–3 RPC calls, and all subsequent reads are synchronous from cache.
|
|
26
6
|
|
|
27
7
|
## ❯ Install
|
|
28
8
|
|
|
@@ -30,54 +10,610 @@ Notes:
|
|
|
30
10
|
$ npm install --save curvance
|
|
31
11
|
```
|
|
32
12
|
|
|
33
|
-
## ❯
|
|
13
|
+
## ❯ Supported Chains
|
|
34
14
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
15
|
+
Chain identifiers use Alchemy-style prefixes:
|
|
16
|
+
|
|
17
|
+
| Chain | Identifier |
|
|
18
|
+
|---|---|
|
|
19
|
+
| Monad Mainnet | `monad-mainnet` |
|
|
20
|
+
| Arbitrum Sepolia | `arb-sepolia` |
|
|
21
|
+
|
|
22
|
+
## ❯ Quick Start
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
import { setupChain } from "curvance";
|
|
26
|
+
import { ethers } from "ethers";
|
|
27
|
+
|
|
28
|
+
const wallet = new ethers.Wallet(privateKey, provider);
|
|
29
|
+
const { markets, reader, dexAgg, global_milestone } = await setupChain("monad-mainnet", wallet);
|
|
39
30
|
```
|
|
40
31
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
32
|
+
`setupChain` signature:
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
setupChain(
|
|
36
|
+
chain: ChainRpcPrefix,
|
|
37
|
+
provider: curvance_provider | null = null, // null → SDK constructs a JsonRpcProvider
|
|
38
|
+
approval_protection: boolean = false, // revoke-before-approve pattern
|
|
39
|
+
api_url: string = "https://api.curvance.com",
|
|
40
|
+
options: { feePolicy?: FeePolicy } = {}
|
|
41
|
+
): Promise<{
|
|
42
|
+
markets: Market[],
|
|
43
|
+
reader: ProtocolReader,
|
|
44
|
+
dexAgg: IDexAgg,
|
|
45
|
+
global_milestone: MilestoneResponse | null
|
|
46
|
+
}>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Explore markets
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
for (const market of markets) {
|
|
53
|
+
console.log(`${market.name} | tvl: ${market.tvl} | debt: ${market.totalDebt}`);
|
|
54
|
+
for (const token of market.tokens) {
|
|
55
|
+
console.log(` ${token.symbol} | price: ${token.getPrice()} | apy: ${token.getApy(true)}%`);
|
|
49
56
|
}
|
|
50
|
-
count++;
|
|
51
57
|
}
|
|
52
58
|
```
|
|
53
59
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
60
|
+
## ❯ Providers
|
|
61
|
+
|
|
62
|
+
`curvance_provider` accepts any ethers v6 provider or signer. All providers are automatically wrapped with retry logic (exponential backoff for rate limits and 5xx errors).
|
|
63
|
+
|
|
64
|
+
| Type | Use case |
|
|
65
|
+
|---|---|
|
|
66
|
+
| `ethers.Wallet` | CLI / server-side with private key |
|
|
67
|
+
| `ethers.JsonRpcSigner` | Browser wallet (MetaMask, etc.) |
|
|
68
|
+
| `ethers.JsonRpcProvider` | Read-only or custom RPC |
|
|
69
|
+
| `null` | SDK constructs a provider from chain config |
|
|
70
|
+
|
|
71
|
+
`curvance_signer` = `JsonRpcSigner | Wallet` — required for write operations (deposit, borrow, etc.)
|
|
72
|
+
|
|
73
|
+
## ❯ Markets
|
|
74
|
+
|
|
75
|
+
`Market` is the top-level container. Each market groups related collateral and borrow tokens and tracks the user's aggregate position.
|
|
76
|
+
|
|
77
|
+
### Market properties
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
market.name // market name
|
|
81
|
+
market.address // market contract address
|
|
82
|
+
market.tvl // total value locked (USD, Decimal)
|
|
83
|
+
market.totalDebt // total outstanding debt (USD, Decimal)
|
|
84
|
+
market.totalCollateral // total posted collateral (USD, Decimal)
|
|
85
|
+
market.cooldownLength // hold period between actions (20 min)
|
|
86
|
+
market.hasBorrowing() // whether this market supports borrowing
|
|
87
|
+
market.highestApy() // best supply APY across all tokens
|
|
88
|
+
market.ltv // LTV range {min, max} or single value
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### User position (all in USD as `Decimal`)
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
market.userDeposits // total deposits
|
|
95
|
+
market.userDebt // total outstanding debt
|
|
96
|
+
market.userMaxDebt // maximum allowable debt
|
|
97
|
+
market.userRemainingCredit // available borrow capacity (with 0.1% buffer)
|
|
98
|
+
market.userCollateral // posted collateral (in shares)
|
|
99
|
+
market.positionHealth // health factor — null means infinite (no debt)
|
|
100
|
+
market.userNet // deposits - debt
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Rate tracking
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
// rateType: 'day' | 'week' | 'month' | 'year'
|
|
107
|
+
market.getUserDepositsChange('week') // projected earnings
|
|
108
|
+
market.getUserDebtChange('week') // projected interest cost
|
|
109
|
+
market.getUserNetChange('week') // net projected change
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Data refresh
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
await market.reloadMarketData() // refresh rates, prices, utilization
|
|
116
|
+
await market.reloadUserData(account) // refresh user balances and position
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## ❯ Tokens (CToken / BorrowableCToken)
|
|
120
|
+
|
|
121
|
+
Tokens within a market are either `CToken` (collateral/supply side) or `BorrowableCToken` (extends `CToken` with borrow/repay). Access them via `market.tokens` or `market.getBorrowableCTokens()`.
|
|
122
|
+
|
|
123
|
+
### Token metadata
|
|
124
|
+
|
|
125
|
+
```ts
|
|
126
|
+
token.symbol
|
|
127
|
+
token.name
|
|
128
|
+
token.decimals
|
|
129
|
+
token.asset // underlying ERC20 address
|
|
130
|
+
token.isBorrowable // whether this token can be borrowed
|
|
131
|
+
token.isVault // whether underlying is an ERC4626 vault
|
|
132
|
+
token.isNativeVault // native token vault (e.g. shMON)
|
|
133
|
+
token.canZap // supports zap deposits
|
|
134
|
+
token.canLeverage // supports leverage
|
|
135
|
+
token.maxLeverage // max allowed leverage (Decimal)
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Market state
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
token.exchangeRate // current share-to-asset rate
|
|
142
|
+
token.totalAssets // total assets held (bigint)
|
|
143
|
+
token.totalSupply // total shares outstanding (bigint)
|
|
144
|
+
token.borrowPaused
|
|
145
|
+
token.collateralizationPaused
|
|
146
|
+
token.mintPaused
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Prices & conversions
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
token.getPrice() // asset price (USD, Decimal)
|
|
153
|
+
token.getPrice(true) // share price
|
|
154
|
+
token.convertTokensToUsd(amount) // TokenInput → USD
|
|
155
|
+
token.convertUsdToTokens(usd) // USD → TokenInput
|
|
156
|
+
token.convertTokenInputToShares(amount) // user input → shares
|
|
157
|
+
token.virtualConvertToAssets(shares) // shares → assets (cached, no RPC)
|
|
158
|
+
token.virtualConvertToShares(assets) // assets → shares (cached, no RPC)
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### User balances
|
|
162
|
+
|
|
163
|
+
```ts
|
|
164
|
+
token.getUserShareBalance(inUSD) // cToken balance
|
|
165
|
+
token.getUserAssetBalance(inUSD) // underlying asset balance
|
|
166
|
+
token.getUserUnderlyingBalance(inUSD) // underlying token balance
|
|
167
|
+
token.getUserCollateral(inUSD) // posted collateral
|
|
168
|
+
token.getUserDebt(inUSD) // outstanding debt (borrow tokens)
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Market totals & caps
|
|
172
|
+
|
|
173
|
+
```ts
|
|
174
|
+
token.getTvl(inUSD)
|
|
175
|
+
token.getTotalCollateral(inUSD)
|
|
176
|
+
token.getCollateralCap(inUSD) // remaining collateral capacity
|
|
177
|
+
token.getDebtCap(inUSD) // remaining debt capacity
|
|
178
|
+
token.getRemainingCollateral(formatted)
|
|
179
|
+
token.getRemainingDebt(formatted)
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Collateral parameters
|
|
183
|
+
|
|
184
|
+
```ts
|
|
185
|
+
token.getCollRatio(inBPS) // collateralization ratio
|
|
186
|
+
token.getCollReqSoft(inBPS) // soft liquidation threshold
|
|
187
|
+
token.getCollReqHard(inBPS) // hard liquidation threshold
|
|
188
|
+
token.getLiqIncBase(inBPS) // liquidation incentive base
|
|
189
|
+
token.getLiqIncMin(inBPS) // liquidation incentive min
|
|
190
|
+
token.getLiqIncMax(inBPS) // liquidation incentive max
|
|
191
|
+
token.liquidationPrice // oracle liquidation price (null = infinite)
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### APY & rates
|
|
195
|
+
|
|
196
|
+
```ts
|
|
197
|
+
token.getApy(asPercentage) // supply APY
|
|
198
|
+
token.getTotalSupplyRate() // supply APY + incentives + native yield
|
|
199
|
+
token.getBorrowRate(inPercentage) // borrow APY
|
|
200
|
+
token.getTotalBorrowRate() // borrow APY minus incentive rewards
|
|
201
|
+
|
|
202
|
+
// BorrowableCToken only
|
|
203
|
+
token.getLiquidity(inUSD) // available liquidity to borrow
|
|
204
|
+
token.getUtilizationRate(inPercentage)
|
|
205
|
+
token.getPredictedBorrowRate(inPercentage)
|
|
206
|
+
token.getMaxBorrowable() // max amount given credit
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Position snapshot & preview
|
|
210
|
+
|
|
211
|
+
```ts
|
|
212
|
+
token.getSnapshot(account) // position snapshot for an account
|
|
213
|
+
token.maxRedemption(inShares, bufferTime) // max redeemable amount
|
|
214
|
+
token.simulateDeposit(amount) // preview deposit without executing
|
|
215
|
+
token.simulateDepositAsCollateral(amount)
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## ❯ Core Operations
|
|
219
|
+
|
|
220
|
+
All amounts are `Decimal` (human-readable token units) unless noted.
|
|
221
|
+
|
|
222
|
+
### Approvals
|
|
223
|
+
|
|
224
|
+
```ts
|
|
225
|
+
await token.approveUnderlying(amount, target) // approve underlying asset spend
|
|
226
|
+
await token.approve(amount, spender) // approve cToken itself
|
|
227
|
+
await token.getAllowance(contract, underlying) // check allowance
|
|
58
228
|
```
|
|
59
229
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
230
|
+
### Deposit & Withdraw
|
|
231
|
+
|
|
232
|
+
```ts
|
|
233
|
+
// Deposit as supplier (earns yield, cannot be used as collateral)
|
|
234
|
+
await token.deposit(amount, zap?, receiver?)
|
|
235
|
+
|
|
236
|
+
// Deposit as collateral (enables borrowing against it)
|
|
237
|
+
await token.depositAsCollateral(amount, zapInstructions?, receiver?)
|
|
238
|
+
|
|
239
|
+
// Withdraw
|
|
240
|
+
await token.redeem(amount) // by asset amount
|
|
241
|
+
await token.redeemShares(amount) // by share amount
|
|
242
|
+
await token.redeemCollateral(amount, receiver?, owner?)
|
|
243
|
+
|
|
244
|
+
// Manage posted collateral
|
|
245
|
+
await token.postCollateral(amount) // post unposted balance as collateral
|
|
246
|
+
await token.removeCollateral(amount, removeAll?)
|
|
67
247
|
```
|
|
68
248
|
|
|
69
|
-
|
|
249
|
+
### Borrow & Repay (`BorrowableCToken` only)
|
|
70
250
|
|
|
251
|
+
```ts
|
|
252
|
+
await borrowToken.borrow(amount, receiver?)
|
|
253
|
+
await borrowToken.repay(amount)
|
|
254
|
+
|
|
255
|
+
// Previews
|
|
256
|
+
const impact = await borrowToken.hypotheticalBorrowOf(amount) // on-chain health preview
|
|
257
|
+
await borrowToken.fetchDebt(inUSD)
|
|
258
|
+
await borrowToken.debtBalance(account)
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### Interest rate model
|
|
262
|
+
|
|
263
|
+
```ts
|
|
264
|
+
await borrowToken.fetchBorrowRate()
|
|
265
|
+
await borrowToken.fetchSupplyRate()
|
|
266
|
+
await borrowToken.fetchUtilizationRate()
|
|
267
|
+
await borrowToken.fetchPredictedBorrowRate()
|
|
268
|
+
await borrowToken.fetchUtilizationRateChange(assets, direction)
|
|
269
|
+
borrowToken.borrowChange(amount, rateType) // interest accrual over time period
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
## ❯ Plugins (Zappers & Position Managers)
|
|
273
|
+
|
|
274
|
+
Zapper and PositionManager contracts must be approved before first use.
|
|
275
|
+
|
|
276
|
+
```ts
|
|
277
|
+
// Check and approve a plugin
|
|
278
|
+
const approved = await token.isPluginApproved('simple', 'zapper')
|
|
279
|
+
if (!approved) await token.approvePlugin('simple', 'zapper')
|
|
280
|
+
|
|
281
|
+
// Plugin types
|
|
282
|
+
// ZapperTypes: 'none' | 'native-vault' | 'vault' | 'simple' | 'native-simple'
|
|
283
|
+
// PositionManagerTypes: 'native-vault' | 'simple' | 'vault'
|
|
284
|
+
|
|
285
|
+
const zapper = token.getZapper('simple')
|
|
286
|
+
const positionManager = token.getPositionManager('simple')
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
## ❯ Zapping (Swap + Deposit)
|
|
290
|
+
|
|
291
|
+
Zap deposits allow depositing any token by swapping to the required underlying via the DEX aggregator.
|
|
292
|
+
|
|
293
|
+
```ts
|
|
294
|
+
// Native token (MON) → deposit
|
|
295
|
+
await token.approvePlugin('native-simple', 'zapper')
|
|
296
|
+
await zapper.nativeZap(ctoken, amount, collateralize)
|
|
297
|
+
|
|
298
|
+
// Any ERC20 → swap → deposit
|
|
299
|
+
await token.approvePlugin('simple', 'zapper')
|
|
300
|
+
await token.approveUnderlying(amount)
|
|
301
|
+
await token.depositAsCollateral(amount, {
|
|
302
|
+
type: 'simple',
|
|
303
|
+
inputToken: inputTokenAddress,
|
|
304
|
+
slippage: new Decimal(0.01) // 1%
|
|
305
|
+
})
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
Check approval status for a zap before executing:
|
|
309
|
+
|
|
310
|
+
```ts
|
|
311
|
+
const approved = await token.isZapAssetApproved(instructions, amount)
|
|
312
|
+
if (!approved) await token.approveZapAsset(instructions, amount)
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
## ❯ Leverage & Deleverage
|
|
316
|
+
|
|
317
|
+
Leverage uses the PositionManager plugin to atomically borrow and swap into the collateral token.
|
|
318
|
+
|
|
319
|
+
```ts
|
|
320
|
+
// One-step: deposit collateral + leverage
|
|
321
|
+
await collateralToken.approveUnderlying(amount)
|
|
322
|
+
await collateralToken.approvePlugin('simple', 'positionManager')
|
|
323
|
+
await collateralToken.depositAndLeverage(amount, borrowToken, targetLeverage, 'simple', slippage)
|
|
324
|
+
|
|
325
|
+
// Separate: deposit first, then leverage
|
|
326
|
+
await collateralToken.depositAsCollateral(amount)
|
|
327
|
+
await collateralToken.leverageUp(borrowToken, new Decimal(3), 'simple', new Decimal(0.005))
|
|
328
|
+
|
|
329
|
+
// Reduce leverage
|
|
330
|
+
await collateralToken.leverageDown(borrowToken, currentLeverage, targetLeverage, 'simple', slippage)
|
|
331
|
+
|
|
332
|
+
// Check current leverage
|
|
333
|
+
collateralToken.getLeverage() // Decimal | null (null if no debt)
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### Leverage previews (via ProtocolReader)
|
|
337
|
+
|
|
338
|
+
```ts
|
|
339
|
+
const preview = await reader.hypotheticalLeverageOf(account, depositCToken, borrowCToken, depositAmount)
|
|
340
|
+
// Returns: { currentLeverage, adjustMaxLeverage, maxLeverage, maxDebtBorrowable }
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
## ❯ Health & Position Previews
|
|
344
|
+
|
|
345
|
+
Preview position health before executing any action. Returns a `Decimal` percentage (0–1) or `null` (infinite / no debt).
|
|
346
|
+
|
|
347
|
+
```ts
|
|
348
|
+
// Individual action previews
|
|
349
|
+
await market.previewPositionHealthDeposit(ctoken, amount)
|
|
350
|
+
await market.previewPositionHealthRedeem(ctoken, amount)
|
|
351
|
+
await market.previewPositionHealthBorrow(borrowToken, amount)
|
|
352
|
+
await market.previewPositionHealthRepay(borrowToken, amount)
|
|
353
|
+
await market.previewPositionHealthLeverageUp(depositCToken, depositAmount, borrowCToken, borrowAmount)
|
|
354
|
+
await market.previewPositionHealthLeverageDown(depositCToken, borrowCToken, newLeverage, currentLeverage)
|
|
355
|
+
|
|
356
|
+
// Generic preview
|
|
357
|
+
await market.previewPositionHealth(depositCToken, borrowCToken, isDeposit, collateralAmt, isRepay, debtAmt, bufferTime)
|
|
358
|
+
|
|
359
|
+
// Projected earnings/cost impact
|
|
360
|
+
await market.previewAssetImpact(user, collateralCToken, debtCToken, depositAmount, borrowAmount, rateType)
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
```ts
|
|
364
|
+
const health = await market.previewPositionHealthBorrow(borrowToken, new Decimal(1000))
|
|
365
|
+
if (health === null) {
|
|
366
|
+
// remains solvent with infinite health
|
|
367
|
+
} else if (health.lt(0.1)) {
|
|
368
|
+
console.warn("Would drop to 10% health — too risky")
|
|
369
|
+
}
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
## ❯ Cooldowns
|
|
373
|
+
|
|
374
|
+
Curvance enforces a 20-minute hold period between certain actions.
|
|
375
|
+
|
|
376
|
+
```ts
|
|
377
|
+
market.cooldown // Date | null (current cooldown expiry)
|
|
378
|
+
await market.expiresAt(account) // fetch cooldown expiry from chain
|
|
379
|
+
await market.multiHoldExpiresAt(markets) // cooldown across multiple markets
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
## ❯ Format Utilities
|
|
383
|
+
|
|
384
|
+
Pure calculation helpers for building UI or simulating outcomes. All accept and return `Decimal`.
|
|
385
|
+
|
|
386
|
+
### Leverage math
|
|
387
|
+
|
|
388
|
+
```ts
|
|
389
|
+
import { leverage } from "curvance"
|
|
390
|
+
|
|
391
|
+
leverage.calculateBorrowAmount(depositUsd, leverageMultiplier)
|
|
392
|
+
leverage.calculateLeverageRatio(totalValue, debtAmount)
|
|
393
|
+
leverage.calculateDeleverageAmount(currentLeverage, targetLeverage, totalValue)
|
|
394
|
+
leverage.calculatePositionSize(tokenAmount, leverageMultiplier)
|
|
395
|
+
leverage.validateLeverageInput(input) // checks balance, min deposit, max leverage, liquidity
|
|
396
|
+
leverage.checkLeverageAmountBelowMinimum(input) // $10.10 minimum borrow
|
|
397
|
+
leverage.checkBorrowExceedsLiquidity(borrowAmount, availableLiquidity)
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
### Borrow math
|
|
401
|
+
|
|
402
|
+
```ts
|
|
403
|
+
import { borrow } from "curvance"
|
|
404
|
+
|
|
405
|
+
borrow.calculateMaxBorrow(remainingCredit, remainingDebt, availableLiquidity)
|
|
406
|
+
borrow.calculateMaxRepay(userBalance, userDebt)
|
|
407
|
+
borrow.validateRepayRemainder(currentDebtUsd, repayAmountUsd) // enforces $10 minimum remainder
|
|
408
|
+
borrow.calculateDebtPreview(currentDebt, amount, isRepaying)
|
|
409
|
+
borrow.convertAmountByCurrencyView(amount, price, currencyView) // USD ↔ token view
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
### Collateral math
|
|
413
|
+
|
|
414
|
+
```ts
|
|
415
|
+
import { collateral } from "curvance"
|
|
416
|
+
|
|
417
|
+
collateral.calculateExchangeRate(assetBalance, shareBalance)
|
|
418
|
+
collateral.calculateCollateralBreakdown(assetBalance, shares, exchangeRate)
|
|
419
|
+
collateral.calculateNewCollateral(currentCollateral, amount, action)
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
### Health display
|
|
423
|
+
|
|
424
|
+
```ts
|
|
425
|
+
import { health } from "curvance"
|
|
426
|
+
|
|
427
|
+
health.getHealthStatus(percentageValue) // 'Danger' | 'Caution' | 'Healthy'
|
|
428
|
+
health.healthFactorToPercentage(rawFactor)
|
|
429
|
+
health.formatHealthFactorPercentage(value)
|
|
430
|
+
health.formatHealthFactor(value) // handles infinity
|
|
431
|
+
health.getLiquidityStatus(ratio) // 'green' | 'yellow' | 'red'
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
### Amount formatting
|
|
435
|
+
|
|
436
|
+
```ts
|
|
437
|
+
import { amounts } from "curvance"
|
|
438
|
+
|
|
439
|
+
amounts.clampUsdDustAmount(value) // zero out sub-$0.01 amounts
|
|
440
|
+
amounts.normalizeAmountString(value, maxFractionDigits, roundingMode)
|
|
441
|
+
amounts.normalizeCurrencyAmounts({ amount, currencyView, tokenDecimals, price })
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
## ❯ Helpers & Utilities
|
|
445
|
+
|
|
446
|
+
```ts
|
|
447
|
+
import {
|
|
448
|
+
getContractAddresses,
|
|
449
|
+
contractSetup,
|
|
450
|
+
handleTransactionWithOracles,
|
|
451
|
+
toDecimal, toBigInt,
|
|
452
|
+
getDepositApy, getBorrowCost,
|
|
453
|
+
getInterestYield, getNativeYield,
|
|
454
|
+
getMerklDepositIncentives, getMerklBorrowIncentives,
|
|
455
|
+
getRateSeconds,
|
|
456
|
+
WAD, WAD_DECIMAL, BPS, RAY,
|
|
457
|
+
UINT256_MAX, EMPTY_ADDRESS, NATIVE_ADDRESS,
|
|
458
|
+
DEFAULT_SLIPPAGE_BPS,
|
|
459
|
+
} from "curvance"
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
| Helper | Description |
|
|
463
|
+
|---|---|
|
|
464
|
+
| `getContractAddresses(chain)` | All contract addresses for a chain |
|
|
465
|
+
| `contractSetup(provider, address, abi)` | Create a typed contract instance |
|
|
466
|
+
| `handleTransactionWithOracles(...)` | Wraps a tx in a Redstone multicall when a pull oracle price write is required |
|
|
467
|
+
| `toDecimal(value, decimals)` | `bigint` → `Decimal` |
|
|
468
|
+
| `toBigInt(value, decimals)` | `Decimal` → `bigint` |
|
|
469
|
+
| `getDepositApy(token, opportunities, apyOverrides)` | Total deposit yield (interest + Merkl + native) |
|
|
470
|
+
| `getBorrowCost(token, opportunities)` | Net borrow cost — may be negative when rewards exceed rate |
|
|
471
|
+
| `getInterestYield(token)` | Lending APY only |
|
|
472
|
+
| `getNativeYield(token, apyOverrides)` | Native yield component |
|
|
473
|
+
| `getMerklDepositIncentives(tokenAddress, opportunities)` | Merkl reward APR for deposits |
|
|
474
|
+
| `getMerklBorrowIncentives(tokenAddress, opportunities)` | Merkl reward APR for borrows |
|
|
475
|
+
| `getRateSeconds(rateType)` | Convert `'year' \| 'month' \| 'week' \| 'day'` → seconds |
|
|
476
|
+
|
|
477
|
+
## ❯ Fee Policy
|
|
478
|
+
|
|
479
|
+
The SDK supports configurable fees applied at the DEX aggregator layer for swaps. Fees are denominated in BPS of the swap input and charged on leverage, deleverage, deposit+leverage, and zap operations.
|
|
480
|
+
|
|
481
|
+
```ts
|
|
482
|
+
import { flatFeePolicy, NO_FEE_POLICY } from "curvance"
|
|
483
|
+
|
|
484
|
+
const feePolicy = flatFeePolicy({
|
|
485
|
+
bps: 10n, // 0.1% default fee
|
|
486
|
+
feeReceiver: "0xYourAddress",
|
|
487
|
+
chain: "monad-mainnet",
|
|
488
|
+
stableToStableBps: 2n, // optional lower fee for stable↔stable swaps
|
|
489
|
+
})
|
|
490
|
+
|
|
491
|
+
const { markets } = await setupChain("monad-mainnet", wallet, false, undefined, { feePolicy })
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
The SDK automatically returns 0 bps for native ↔ wrapped-native swaps and same-token no-op zaps.
|
|
495
|
+
|
|
496
|
+
```ts
|
|
497
|
+
// FeePolicy interface — implement your own
|
|
498
|
+
interface FeePolicy {
|
|
499
|
+
feeReceiver: address;
|
|
500
|
+
getFeeBps(ctx: FeePolicyContext): bigint;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
// Context passed to getFeeBps
|
|
504
|
+
interface FeePolicyContext {
|
|
505
|
+
operation: 'leverage-up' | 'leverage-down' | 'deposit-and-leverage' | 'zap';
|
|
506
|
+
inputToken: address;
|
|
507
|
+
outputToken: address;
|
|
508
|
+
inputAmount: bigint;
|
|
509
|
+
currentLeverage: Decimal | null;
|
|
510
|
+
targetLeverage: Decimal | null;
|
|
511
|
+
}
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
## ❯ Integrations
|
|
515
|
+
|
|
516
|
+
### Merkl rewards
|
|
517
|
+
|
|
518
|
+
```ts
|
|
519
|
+
import { fetchMerklOpportunities, fetchMerklUserRewards, fetchMerklCampaignsBySymbol } from "curvance"
|
|
520
|
+
|
|
521
|
+
// All active opportunities (APR, token, type)
|
|
522
|
+
const opportunities = await fetchMerklOpportunities()
|
|
523
|
+
|
|
524
|
+
// Pending rewards for a user
|
|
525
|
+
const rewards = await fetchMerklUserRewards({ wallet: address, chainId: 143 })
|
|
526
|
+
|
|
527
|
+
// Campaigns for a specific token
|
|
528
|
+
const campaigns = await fetchMerklCampaignsBySymbol({ tokenSymbol: "USDC" })
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
### Portfolio snapshots
|
|
532
|
+
|
|
533
|
+
```ts
|
|
534
|
+
import { takePortfolioSnapshot, snapshotMarket } from "curvance"
|
|
535
|
+
|
|
536
|
+
// Full portfolio across all markets
|
|
537
|
+
const snapshot = await takePortfolioSnapshot(account)
|
|
538
|
+
// Returns: { account, chain, timestamp, totalDepositsUSD, totalDebtUSD, netUSD, dailyEarnings, dailyCost, markets[] }
|
|
539
|
+
|
|
540
|
+
// Single market
|
|
541
|
+
const marketSnapshot = snapshotMarket(market)
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
## ❯ Optimizer
|
|
545
|
+
|
|
546
|
+
The `OptimizerReader` reads yield-rebalancing vaults that allocate across markets.
|
|
547
|
+
|
|
548
|
+
```ts
|
|
549
|
+
import { OptimizerReader } from "curvance"
|
|
550
|
+
|
|
551
|
+
const optimizer = new OptimizerReader(provider)
|
|
552
|
+
|
|
553
|
+
await optimizer.getOptimizerMarketData(optimizerAddresses)
|
|
554
|
+
// Returns: { totalAssets, sharePrice, performanceFee, markets[] }
|
|
555
|
+
|
|
556
|
+
await optimizer.getOptimizerUserData(optimizerAddresses, account)
|
|
557
|
+
// Returns: user balance and redeemable amounts
|
|
558
|
+
|
|
559
|
+
await optimizer.optimalDeposit(optimizer, assets) // best market to deposit into
|
|
560
|
+
await optimizer.optimalWithdrawal(optimizer, assets) // best market to withdraw from
|
|
561
|
+
await optimizer.optimalRebalance(optimizer) // suggested reallocations: { cToken, assets }[]
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
## ❯ TypeScript Types
|
|
565
|
+
|
|
566
|
+
```ts
|
|
567
|
+
// Primitives
|
|
568
|
+
type address = `0x${string}` // checksummed Ethereum address
|
|
569
|
+
type bytes = `0x${string}` // hex-encoded calldata
|
|
570
|
+
type Percentage = Decimal // 0–1, e.g. 0.7 = 70%
|
|
571
|
+
type USD = Decimal // human-readable USD (1.0 = $1)
|
|
572
|
+
type USD_WAD = bigint // USD in 1e18 WAD format
|
|
573
|
+
type TokenInput = Decimal // human-readable token amount
|
|
574
|
+
type TypeBPS = bigint // basis points (10000 = 100%)
|
|
575
|
+
type ChainRpcPrefix = "monad-mainnet" | "arb-sepolia"
|
|
576
|
+
type curvance_provider = JsonRpcSigner | Wallet | JsonRpcProvider
|
|
577
|
+
type curvance_signer = JsonRpcSigner | Wallet
|
|
578
|
+
|
|
579
|
+
// Market categorization
|
|
580
|
+
type MarketCategory = "stablecoin" | "staking" | "restaking" | "yield-stablecoin" | "blue-chip" | "native"
|
|
581
|
+
type CollateralSource = "Renzo" | "Upshift" | "Yuzu" | "Native" | "Circle" | "Fastlane" | "Apriori" | "Mu Digital" | "Kintsu" | "Reservoir"
|
|
582
|
+
|
|
583
|
+
// Operations
|
|
584
|
+
type ZapperTypes = 'none' | 'native-vault' | 'vault' | 'simple' | 'native-simple'
|
|
585
|
+
type PositionManagerTypes = 'native-vault' | 'simple' | 'vault'
|
|
586
|
+
type ChangeRate = 'year' | 'month' | 'week' | 'day'
|
|
587
|
+
|
|
588
|
+
// DEX
|
|
589
|
+
interface Quote {
|
|
590
|
+
to: address
|
|
591
|
+
calldata: bytes
|
|
592
|
+
min_out: bigint
|
|
593
|
+
out: bigint
|
|
594
|
+
}
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
All numeric return values are `bigint` or `Decimal` — never plain JS `number`.
|
|
598
|
+
|
|
599
|
+
## ❯ Constants
|
|
600
|
+
|
|
601
|
+
```ts
|
|
602
|
+
WAD // 1_000_000_000_000_000_000n (1e18)
|
|
603
|
+
BPS // 10_000n
|
|
604
|
+
RAY // 1_000_000_000_000_000_000_000_000_000n (1e27)
|
|
605
|
+
WAD_SQUARED // 1e36n
|
|
606
|
+
WAD_DECIMAL // Decimal('1e18')
|
|
607
|
+
UINT256_MAX
|
|
608
|
+
EMPTY_ADDRESS // '0x0000000000000000000000000000000000000000'
|
|
609
|
+
NATIVE_ADDRESS // canonical native token address
|
|
610
|
+
DEFAULT_SLIPPAGE_BPS // 100n (1%)
|
|
611
|
+
```
|
|
71
612
|
|
|
72
|
-
|
|
73
|
-
- `getContractAddresses` - Grab the contracts addresses for a given chain
|
|
74
|
-
- `AdaptorTypes` - Adaptor identifier enums
|
|
75
|
-
- `WAD` - WAD amount
|
|
76
|
-
- `WAD_DECIMAL` - WAD amount as Decimal.js type
|
|
77
|
-
- `contractSetup` - Used to initialize contract & attach typescript interface
|
|
78
|
-
- `handleTransactionWithOracles` - Depending on what adaptor is being used to execute the function we choose to run a multi-call that will write-price on-chain with the given function -- but only if the adaptor is the type of adaptor that requires this (pull oracle)
|
|
613
|
+
## ❯ Dependencies
|
|
79
614
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
615
|
+
| Package | Purpose |
|
|
616
|
+
|---|---|
|
|
617
|
+
| [ethers v6](https://www.npmjs.com/package/ethers) | Typed contract interactions, providers, and signer handling |
|
|
618
|
+
| [decimal.js](https://www.npmjs.com/package/decimal.js) | Arbitrary-precision math for all token amounts, prices, and rates |
|
|
619
|
+
| [@redstone-finance/sdk](https://www.npmjs.com/package/@redstone-finance/sdk) | Price feed writes bundled into multicalls for pull-oracle adaptors |
|