@kasufinance/kasu-sdk 2.5.0 → 2.7.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 +144 -7
- package/dist/bundle.cjs.js +1667 -21
- package/dist/bundle.esm.js +1630 -22
- package/dist/domain/au-minimum.d.ts +135 -0
- package/dist/domain/au-minimum.js +154 -0
- package/dist/domain/au-minimum.js.map +1 -0
- package/dist/domain/index.d.ts +18 -3
- package/dist/domain/index.js +13 -3
- package/dist/domain/index.js.map +1 -1
- package/dist/domain/loan-contract.d.ts +174 -0
- package/dist/domain/loan-contract.js +160 -0
- package/dist/domain/loan-contract.js.map +1 -0
- package/dist/domain/requests.d.ts +219 -0
- package/dist/domain/requests.js +218 -0
- package/dist/domain/requests.js.map +1 -0
- package/dist/domain/settlement.d.ts +97 -0
- package/dist/domain/settlement.js +117 -0
- package/dist/domain/settlement.js.map +1 -0
- package/dist/domain/wallet-errors.d.ts +92 -0
- package/dist/domain/wallet-errors.js +155 -0
- package/dist/domain/wallet-errors.js.map +1 -0
- package/dist/facade/chain-configs.js +7 -1
- package/dist/facade/chain-configs.js.map +1 -1
- package/dist/facade/deposits.js +2 -1
- package/dist/facade/deposits.js.map +1 -1
- package/dist/facade/flows.d.ts +95 -0
- package/dist/facade/flows.js +116 -0
- package/dist/facade/flows.js.map +1 -0
- package/dist/facade/index.d.ts +3 -0
- package/dist/facade/index.js +3 -0
- package/dist/facade/index.js.map +1 -1
- package/dist/facade/kasu.d.ts +6 -2
- package/dist/facade/kasu.js +28 -3
- package/dist/facade/kasu.js.map +1 -1
- package/dist/facade/read-only.d.ts +12 -0
- package/dist/facade/read-only.js +13 -0
- package/dist/facade/read-only.js.map +1 -0
- package/dist/facade/user-portfolio.d.ts +18 -0
- package/dist/facade/user-portfolio.js +23 -0
- package/dist/facade/user-portfolio.js.map +1 -1
- package/dist/flows/deposit-flow.d.ts +301 -0
- package/dist/flows/deposit-flow.js +358 -0
- package/dist/flows/deposit-flow.js.map +1 -0
- package/dist/flows/flow.d.ts +72 -0
- package/dist/flows/flow.js +110 -0
- package/dist/flows/flow.js.map +1 -0
- package/dist/flows/index.d.ts +19 -0
- package/dist/flows/index.js +17 -0
- package/dist/flows/index.js.map +1 -0
- package/dist/flows/observable.d.ts +59 -0
- package/dist/flows/observable.js +81 -0
- package/dist/flows/observable.js.map +1 -0
- package/dist/flows/withdraw-flow.d.ts +99 -0
- package/dist/flows/withdraw-flow.js +83 -0
- package/dist/flows/withdraw-flow.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/services/DataService/data-service.js +3 -11
- package/dist/services/DataService/data-service.js.map +1 -1
- package/dist/services/DataService/directus-client.d.ts +26 -0
- package/dist/services/DataService/directus-client.js +38 -0
- package/dist/services/DataService/directus-client.js.map +1 -0
- package/dist/services/UserLending/user-lending.js +11 -7
- package/dist/services/UserLending/user-lending.js.map +1 -1
- package/package.json +8 -2
- package/src/domain/au-minimum.ts +192 -0
- package/src/domain/index.ts +73 -3
- package/src/domain/loan-contract.ts +275 -0
- package/src/domain/requests.ts +467 -0
- package/src/domain/settlement.ts +161 -0
- package/src/domain/wallet-errors.ts +173 -0
- package/src/facade/chain-configs.ts +7 -1
- package/src/facade/deposits.ts +2 -3
- package/src/facade/flows.ts +172 -0
- package/src/facade/index.ts +8 -0
- package/src/facade/kasu.ts +43 -3
- package/src/facade/read-only.ts +13 -0
- package/src/facade/user-portfolio.ts +24 -0
- package/src/flows/deposit-flow.ts +775 -0
- package/src/flows/flow.ts +108 -0
- package/src/flows/index.ts +45 -0
- package/src/flows/observable.ts +97 -0
- package/src/flows/withdraw-flow.ts +210 -0
- package/src/index.ts +9 -0
- package/src/services/DataService/data-service.ts +7 -25
- package/src/services/DataService/directus-client.ts +54 -0
- package/src/services/UserLending/user-lending.ts +17 -21
- package/dist/domain/deposit-bounds.test.d.ts +0 -1
- package/dist/domain/deposit-bounds.test.js +0 -135
- package/dist/domain/deposit-bounds.test.js.map +0 -1
- package/dist/domain/partners.test.d.ts +0 -1
- package/dist/domain/partners.test.js +0 -53
- package/dist/domain/partners.test.js.map +0 -1
- package/dist/domain/pools.test.d.ts +0 -1
- package/dist/domain/pools.test.js +0 -184
- package/dist/domain/pools.test.js.map +0 -1
- package/dist/domain/rates.test.d.ts +0 -1
- package/dist/domain/rates.test.js +0 -181
- package/dist/domain/rates.test.js.map +0 -1
- package/dist/domain/tranche-display-name.test.d.ts +0 -1
- package/dist/domain/tranche-display-name.test.js +0 -58
- package/dist/domain/tranche-display-name.test.js.map +0 -1
- package/dist/domain/tranches.test.d.ts +0 -1
- package/dist/domain/tranches.test.js +0 -206
- package/dist/domain/tranches.test.js.map +0 -1
- package/dist/facade/config.test.d.ts +0 -1
- package/dist/facade/config.test.js +0 -216
- package/dist/facade/config.test.js.map +0 -1
- package/dist/facade/facade.test.d.ts +0 -1
- package/dist/facade/facade.test.js +0 -201
- package/dist/facade/facade.test.js.map +0 -1
- package/dist/services/Locking/calculate-apy.test.d.ts +0 -1
- package/dist/services/Locking/calculate-apy.test.js +0 -41
- package/dist/services/Locking/calculate-apy.test.js.map +0 -1
- package/dist/tests/sample.test.d.ts +0 -1
- package/dist/tests/sample.test.js +0 -59
- package/dist/tests/sample.test.js.map +0 -1
- package/src/domain/deposit-bounds.test.ts +0 -200
- package/src/domain/partners.test.ts +0 -83
- package/src/domain/pools.test.ts +0 -260
- package/src/domain/rates.test.ts +0 -254
- package/src/domain/tranche-display-name.test.ts +0 -96
- package/src/domain/tranches.test.ts +0 -300
- package/src/facade/config.test.ts +0 -265
- package/src/facade/facade.test.ts +0 -250
- package/src/services/Locking/calculate-apy.test.ts +0 -52
- package/src/tests/sample.test.ts +0 -63
package/README.md
CHANGED
|
@@ -8,9 +8,10 @@
|
|
|
8
8
|
real-world credit funded on-chain. It wraps the core contracts, the subgraphs
|
|
9
9
|
and the CMS behind one object, so an application can list lending strategies,
|
|
10
10
|
read a lender's positions and submit KYC-gated deposits and withdrawals without
|
|
11
|
-
re-implementing the plumbing. It also ships a pure domain layer
|
|
11
|
+
re-implementing the plumbing. It also ships a pure domain layer — the rate,
|
|
12
12
|
tranche and pool rules every Kasu frontend agrees on, as numbers rather than
|
|
13
|
-
copy
|
|
13
|
+
copy — and headless deposit and withdrawal flows that own the ORDER of those
|
|
14
|
+
transactions so no application has to.
|
|
14
15
|
|
|
15
16
|
## Installation
|
|
16
17
|
|
|
@@ -116,7 +117,8 @@ You can also pass a whole `ChainConfigEntry` instead of a chain key.
|
|
|
116
117
|
| ----------------- | ----------------------------------------------------------------------------------------------------------------------- | ------------------------------- |
|
|
117
118
|
| `kasu.strategies` | `getAll()`, `getVisible()`, `getById()`, `getPlatformStats()`, `getPerformanceFeePercent()`, `calculateDepositLimits()` | Browse pools, APY, capacity |
|
|
118
119
|
| `kasu.deposits` | `deposit()`, `withdraw()`, `withdrawMax()`, `buildKycParams()`, `isClearingPending()` | Submit transactions |
|
|
119
|
-
| `kasu.portfolio` | `getPositions()`, `getTransactionHistory()`
|
|
120
|
+
| `kasu.portfolio` | `getPositions()`, `getTransactionHistory()`, `getRequestStates()` | Lender balances, yield, history |
|
|
121
|
+
| `kasu.flows` | `deposit(ports)`, `withdraw(ports?)` | Headless transaction pipelines |
|
|
120
122
|
|
|
121
123
|
On the instance itself: `kasu.connect(signer)`, `kasu.isReadOnly`,
|
|
122
124
|
`kasu.provider`, `kasu.chainConfig`, `kasu.isLiteDeployment`, and
|
|
@@ -142,9 +144,20 @@ application formats them in its own design system and language.
|
|
|
142
144
|
| Pools | `selectVisiblePools`, `poolMaxApy`, `pickHighestYieldTranche`, `maxNetRateCeiling` |
|
|
143
145
|
| Partners | `getCreditOriginator`, `getInstitutionalLender`, `APXIUM`, `INVOICEMATE`, `RIXON_CAPITAL` |
|
|
144
146
|
| Tranche display name | `getTrancheDisplayName`, `UPPER_MEZZANINE` |
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
147
|
+
| Requests | `deriveRequestState`, `submissionEvents`, `countSubmissions`, `firstSubmissionTimestamp`, `isCycleClosed` |
|
|
148
|
+
| Settlement | `computeSettlementWindow`, `nextCycleBoundary`, `deriveCycleDates`, `CLEARING_WINDOW_SECONDS` |
|
|
149
|
+
| Loan contract | `encodeDepositData`, `buildContractVersionType`, `buildLoanAgreementSignMessage`, `buildLegacyContractRequestMessage`, `buildFullNameRequestMessage`, `formatSignTimestampUtc`, `parseFormattedMessage`, `asContractType` |
|
|
150
|
+
| Wallet errors | `isUserRejected`, `isUnpredictableGas` |
|
|
151
|
+
| AU minimum | `auMinimumRemaining`, `isAustralianKyc`, `auThresholdFor`, `isAuMinimumExempt`, `parseMinorUnits`, `AU_ALPHA3`, `AU_MIN_CUMULATIVE_BY_STABLE` |
|
|
152
|
+
|
|
153
|
+
Three rules worth knowing:
|
|
154
|
+
|
|
155
|
+
- **Protocol strings are the exception to "never copy".** The messages
|
|
156
|
+
`loan-contract` builds are reconstructed byte-for-byte by the Kasu backend to
|
|
157
|
+
verify a lender's signature, and `encodeDepositData` produces bytes that go
|
|
158
|
+
on chain. They are not text to translate or tidy: a changed word, separator
|
|
159
|
+
or date format stops signatures verifying. Everything else in this layer is
|
|
160
|
+
numbers and codes.
|
|
148
161
|
- **Rates fail closed.** `netEffectiveApy`, `netTrancheApyBounds` and
|
|
149
162
|
`maxNetRateCeiling` return `NaN` / `null` rather than a plausible-looking
|
|
150
163
|
wrong number when an input is out of domain. Render that as "no rate", never
|
|
@@ -153,7 +166,131 @@ Two rules worth knowing:
|
|
|
153
166
|
- **The tranche rename is display-only.** `getTrancheDisplayName` maps the
|
|
154
167
|
`Senior` tranche to "Upper Mezzanine" on Apxium strategies, because the true
|
|
155
168
|
senior position is held by an institutional lender. Call it at the view
|
|
156
|
-
boundary only: ranking, matching and sorting keep the raw on-chain name
|
|
169
|
+
boundary only: ranking, matching and sorting keep the raw on-chain name —
|
|
170
|
+
which is why `deriveRequestState` returns `trancheName` raw — and
|
|
171
|
+
`reallocationTargetTrancheName` with it.
|
|
172
|
+
|
|
173
|
+
## Flows
|
|
174
|
+
|
|
175
|
+
`DepositFlow` and `WithdrawFlow` are the domain layer one level up: a rule that
|
|
176
|
+
unfolds over TIME. They own the order of a deposit and a withdrawal, the guards
|
|
177
|
+
around them, and the codes that describe where a run got to. They own no UI, no
|
|
178
|
+
framework, no network and **no copy** — every observable state is a code, and
|
|
179
|
+
your application maps it to its own words in its own language.
|
|
180
|
+
|
|
181
|
+
Every side effect is an injected port, so the SDK never learns a URL, a key or
|
|
182
|
+
a wallet. `kasu.flows.deposit()` fills the ports it can from this instance; the
|
|
183
|
+
three that reach your own backend or wallet you always supply.
|
|
184
|
+
|
|
185
|
+
```ts
|
|
186
|
+
import { Kasu } from '@kasufinance/kasu-sdk';
|
|
187
|
+
import { parseUnits } from 'ethers/lib/utils';
|
|
188
|
+
|
|
189
|
+
const kasu = Kasu.create({ chain: 'base' }).connect(signer);
|
|
190
|
+
|
|
191
|
+
const flow = kasu.flows.deposit({
|
|
192
|
+
signMessage: (message) => signer.signMessage(message),
|
|
193
|
+
generateContract: (req) => postJson('/api/agreements/generate', req),
|
|
194
|
+
getKycSignature: (params) => postJson('/api/kyc-signature', params),
|
|
195
|
+
// readAllowance, approve, deposit and buildKycParams default to the SDK's
|
|
196
|
+
// own signer-bound implementations — override any of them if you need to.
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
const stop = flow.subscribe((state) => {
|
|
200
|
+
// Every transition. `state.phase`, `state.step`, `state.stepIndex`,
|
|
201
|
+
// `state.stepTotal`, `state.contract`, `state.failure` — all codes.
|
|
202
|
+
render(state);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
await flow.start({
|
|
206
|
+
poolId,
|
|
207
|
+
trancheId,
|
|
208
|
+
amount: parseUnits('1000', 6), // BASE units
|
|
209
|
+
fixedTermConfigId: '0', // '0' = variable rate
|
|
210
|
+
userAddress,
|
|
211
|
+
depositAmount: 1000, // display units, for the backend's integrity check
|
|
212
|
+
contractMessage: {
|
|
213
|
+
format: 'loan-agreement',
|
|
214
|
+
strategyName,
|
|
215
|
+
region,
|
|
216
|
+
optionName,
|
|
217
|
+
amountLabel, // built from the SAME value as depositAmount
|
|
218
|
+
},
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
// The run PARKS on `awaiting-accept` with the agreement in `state.contract`.
|
|
222
|
+
// Show it, then settle the handshake:
|
|
223
|
+
await flow.acceptContract(); // signs it and carries on
|
|
224
|
+
// or: flow.declineContract(); → phase 'declined', nothing submitted
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
**Phases** — `idle`, `generating-sign`, `generating-fetch`, `awaiting-accept`,
|
|
228
|
+
`accepting-sign`, `approve`, `request-sign`, `request-confirm`, and the
|
|
229
|
+
terminal `success` / `declined` / `error`. Each maps to one of four steps
|
|
230
|
+
(`generate`, `confirm`, `approve`, `request`); `stepIndex` and `stepTotal` are
|
|
231
|
+
published because the approve step drops out of the sequence when the allowance
|
|
232
|
+
already covers the deposit, and a badge total that changed under a lender would
|
|
233
|
+
be describing a pipeline they are not in.
|
|
234
|
+
|
|
235
|
+
**Failures** are codes, never sentences:
|
|
236
|
+
|
|
237
|
+
```ts
|
|
238
|
+
type DepositFailure =
|
|
239
|
+
| { step: DepositStep; reason: 'cancelled' } // isUserRejected
|
|
240
|
+
| { step: DepositStep; reason: 'failed'; error: unknown }
|
|
241
|
+
| { step: 'request'; reason: 'insufficient-balance'; error: unknown }
|
|
242
|
+
| { step: 'request'; reason: 'contract-expired' }; // the 5-minute TTL
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
A wallet rejection is `cancelled`, not a failure: the lender changed their
|
|
246
|
+
mind, and telling them something broke would be a lie. A reverted gas estimate
|
|
247
|
+
on the request step is `insufficient-balance` — nothing was refused, so a retry
|
|
248
|
+
would only reproduce it. Everything else is `failed` and carries the original
|
|
249
|
+
error for your crash reporter.
|
|
250
|
+
|
|
251
|
+
Three guarantees worth knowing:
|
|
252
|
+
|
|
253
|
+
- **The approve is for the EXACT amount, never unlimited.** An unlimited
|
|
254
|
+
allowance outlives the deposit it was granted for; a later exploit of the
|
|
255
|
+
spender would drain a wallet that stopped lending months ago.
|
|
256
|
+
- **The allowance is read live, before anything is signed.** An exact-amount
|
|
257
|
+
approval is fully consumed by the deposit it paid for, so a cached allowance
|
|
258
|
+
is exactly the value that wrongly skips the approve and reverts the deposit.
|
|
259
|
+
- **The spender is the SDK's, not yours.** `kasu.flows.deposit()` defaults it
|
|
260
|
+
to this chain's `LendingPoolManager` — the only contract the default deposit
|
|
261
|
+
port calls — so you no longer pass it. `spender` on the input still
|
|
262
|
+
overrides, for a consumer that replaced the `deposit` port; a wrong one is an
|
|
263
|
+
approval granted to the wrong contract and then a revert you would read as
|
|
264
|
+
`insufficient-balance`.
|
|
265
|
+
- **`reset()` is safe mid-flight, and immediate.** It abandons the run, drops
|
|
266
|
+
its remaining transitions, unparks a waiting handshake and releases the
|
|
267
|
+
re-entry guard in the SAME tick — so `flow.reset(); flow.start(next)` starts
|
|
268
|
+
the next run even when the abandoned one is still parked on a wallet prompt
|
|
269
|
+
that will never answer. An abandoned run can never drive a view you have left
|
|
270
|
+
back to `success`. `start()` is otherwise guarded against re-entry, so a
|
|
271
|
+
double tap cannot fire two deposits.
|
|
272
|
+
- **Only wallet errors can be `cancelled`.** The ports that reach your backend
|
|
273
|
+
— `generateContract`, `buildKycParams`, `getKycSignature` — always fail as
|
|
274
|
+
`failed`, with the error kept. A backend that words a refusal "declined" is
|
|
275
|
+
never reported to a lender as something they did in their wallet.
|
|
276
|
+
|
|
277
|
+
`WithdrawFlow` is the same shape and much smaller — an optional KYC pre-check,
|
|
278
|
+
then `withdraw` or `withdrawMax`, with the same `cancelled` / `failed` split:
|
|
279
|
+
|
|
280
|
+
```ts
|
|
281
|
+
const flow = kasu.flows.withdraw();
|
|
282
|
+
await flow.start({ poolId, trancheId, amount: 'max', userAddress });
|
|
283
|
+
|
|
284
|
+
// With the pre-check: supply `getKycSignature` and the run checks the lender's
|
|
285
|
+
// KYC before opening the wallet, on a `checking-kyc` phase and a `kyc` step.
|
|
286
|
+
// `buildKycParams` defaults to the SDK's, exactly as on the deposit path.
|
|
287
|
+
const checked = kasu.flows.withdraw({
|
|
288
|
+
getKycSignature: (params) => postJson('/api/kyc-signature', params),
|
|
289
|
+
});
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
`'max'` is a code you pass, not a balance you read: it routes to the all-shares
|
|
293
|
+
call, which resolves the balance on chain at execution.
|
|
157
294
|
|
|
158
295
|
## Low-level `KasuSdk`
|
|
159
296
|
|