@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.
Files changed (128) hide show
  1. package/README.md +144 -7
  2. package/dist/bundle.cjs.js +1667 -21
  3. package/dist/bundle.esm.js +1630 -22
  4. package/dist/domain/au-minimum.d.ts +135 -0
  5. package/dist/domain/au-minimum.js +154 -0
  6. package/dist/domain/au-minimum.js.map +1 -0
  7. package/dist/domain/index.d.ts +18 -3
  8. package/dist/domain/index.js +13 -3
  9. package/dist/domain/index.js.map +1 -1
  10. package/dist/domain/loan-contract.d.ts +174 -0
  11. package/dist/domain/loan-contract.js +160 -0
  12. package/dist/domain/loan-contract.js.map +1 -0
  13. package/dist/domain/requests.d.ts +219 -0
  14. package/dist/domain/requests.js +218 -0
  15. package/dist/domain/requests.js.map +1 -0
  16. package/dist/domain/settlement.d.ts +97 -0
  17. package/dist/domain/settlement.js +117 -0
  18. package/dist/domain/settlement.js.map +1 -0
  19. package/dist/domain/wallet-errors.d.ts +92 -0
  20. package/dist/domain/wallet-errors.js +155 -0
  21. package/dist/domain/wallet-errors.js.map +1 -0
  22. package/dist/facade/chain-configs.js +7 -1
  23. package/dist/facade/chain-configs.js.map +1 -1
  24. package/dist/facade/deposits.js +2 -1
  25. package/dist/facade/deposits.js.map +1 -1
  26. package/dist/facade/flows.d.ts +95 -0
  27. package/dist/facade/flows.js +116 -0
  28. package/dist/facade/flows.js.map +1 -0
  29. package/dist/facade/index.d.ts +3 -0
  30. package/dist/facade/index.js +3 -0
  31. package/dist/facade/index.js.map +1 -1
  32. package/dist/facade/kasu.d.ts +6 -2
  33. package/dist/facade/kasu.js +28 -3
  34. package/dist/facade/kasu.js.map +1 -1
  35. package/dist/facade/read-only.d.ts +12 -0
  36. package/dist/facade/read-only.js +13 -0
  37. package/dist/facade/read-only.js.map +1 -0
  38. package/dist/facade/user-portfolio.d.ts +18 -0
  39. package/dist/facade/user-portfolio.js +23 -0
  40. package/dist/facade/user-portfolio.js.map +1 -1
  41. package/dist/flows/deposit-flow.d.ts +301 -0
  42. package/dist/flows/deposit-flow.js +358 -0
  43. package/dist/flows/deposit-flow.js.map +1 -0
  44. package/dist/flows/flow.d.ts +72 -0
  45. package/dist/flows/flow.js +110 -0
  46. package/dist/flows/flow.js.map +1 -0
  47. package/dist/flows/index.d.ts +19 -0
  48. package/dist/flows/index.js +17 -0
  49. package/dist/flows/index.js.map +1 -0
  50. package/dist/flows/observable.d.ts +59 -0
  51. package/dist/flows/observable.js +81 -0
  52. package/dist/flows/observable.js.map +1 -0
  53. package/dist/flows/withdraw-flow.d.ts +99 -0
  54. package/dist/flows/withdraw-flow.js +83 -0
  55. package/dist/flows/withdraw-flow.js.map +1 -0
  56. package/dist/index.d.ts +2 -0
  57. package/dist/index.js +7 -0
  58. package/dist/index.js.map +1 -1
  59. package/dist/services/DataService/data-service.js +3 -11
  60. package/dist/services/DataService/data-service.js.map +1 -1
  61. package/dist/services/DataService/directus-client.d.ts +26 -0
  62. package/dist/services/DataService/directus-client.js +38 -0
  63. package/dist/services/DataService/directus-client.js.map +1 -0
  64. package/dist/services/UserLending/user-lending.js +11 -7
  65. package/dist/services/UserLending/user-lending.js.map +1 -1
  66. package/package.json +8 -2
  67. package/src/domain/au-minimum.ts +192 -0
  68. package/src/domain/index.ts +73 -3
  69. package/src/domain/loan-contract.ts +275 -0
  70. package/src/domain/requests.ts +467 -0
  71. package/src/domain/settlement.ts +161 -0
  72. package/src/domain/wallet-errors.ts +173 -0
  73. package/src/facade/chain-configs.ts +7 -1
  74. package/src/facade/deposits.ts +2 -3
  75. package/src/facade/flows.ts +172 -0
  76. package/src/facade/index.ts +8 -0
  77. package/src/facade/kasu.ts +43 -3
  78. package/src/facade/read-only.ts +13 -0
  79. package/src/facade/user-portfolio.ts +24 -0
  80. package/src/flows/deposit-flow.ts +775 -0
  81. package/src/flows/flow.ts +108 -0
  82. package/src/flows/index.ts +45 -0
  83. package/src/flows/observable.ts +97 -0
  84. package/src/flows/withdraw-flow.ts +210 -0
  85. package/src/index.ts +9 -0
  86. package/src/services/DataService/data-service.ts +7 -25
  87. package/src/services/DataService/directus-client.ts +54 -0
  88. package/src/services/UserLending/user-lending.ts +17 -21
  89. package/dist/domain/deposit-bounds.test.d.ts +0 -1
  90. package/dist/domain/deposit-bounds.test.js +0 -135
  91. package/dist/domain/deposit-bounds.test.js.map +0 -1
  92. package/dist/domain/partners.test.d.ts +0 -1
  93. package/dist/domain/partners.test.js +0 -53
  94. package/dist/domain/partners.test.js.map +0 -1
  95. package/dist/domain/pools.test.d.ts +0 -1
  96. package/dist/domain/pools.test.js +0 -184
  97. package/dist/domain/pools.test.js.map +0 -1
  98. package/dist/domain/rates.test.d.ts +0 -1
  99. package/dist/domain/rates.test.js +0 -181
  100. package/dist/domain/rates.test.js.map +0 -1
  101. package/dist/domain/tranche-display-name.test.d.ts +0 -1
  102. package/dist/domain/tranche-display-name.test.js +0 -58
  103. package/dist/domain/tranche-display-name.test.js.map +0 -1
  104. package/dist/domain/tranches.test.d.ts +0 -1
  105. package/dist/domain/tranches.test.js +0 -206
  106. package/dist/domain/tranches.test.js.map +0 -1
  107. package/dist/facade/config.test.d.ts +0 -1
  108. package/dist/facade/config.test.js +0 -216
  109. package/dist/facade/config.test.js.map +0 -1
  110. package/dist/facade/facade.test.d.ts +0 -1
  111. package/dist/facade/facade.test.js +0 -201
  112. package/dist/facade/facade.test.js.map +0 -1
  113. package/dist/services/Locking/calculate-apy.test.d.ts +0 -1
  114. package/dist/services/Locking/calculate-apy.test.js +0 -41
  115. package/dist/services/Locking/calculate-apy.test.js.map +0 -1
  116. package/dist/tests/sample.test.d.ts +0 -1
  117. package/dist/tests/sample.test.js +0 -59
  118. package/dist/tests/sample.test.js.map +0 -1
  119. package/src/domain/deposit-bounds.test.ts +0 -200
  120. package/src/domain/partners.test.ts +0 -83
  121. package/src/domain/pools.test.ts +0 -260
  122. package/src/domain/rates.test.ts +0 -254
  123. package/src/domain/tranche-display-name.test.ts +0 -96
  124. package/src/domain/tranches.test.ts +0 -300
  125. package/src/facade/config.test.ts +0 -265
  126. package/src/facade/facade.test.ts +0 -250
  127. package/src/services/Locking/calculate-apy.test.ts +0 -52
  128. package/src/tests/sample.test.ts +0 -63
@@ -0,0 +1,301 @@
1
+ import { BigNumber } from 'ethers';
2
+ import { GenerateContractResponse } from '../domain/loan-contract';
3
+ import { DepositParams, KycParams } from '../facade/types';
4
+ import { Flow } from './flow';
5
+ import { WaitableTransaction } from './observable';
6
+ /**
7
+ * The KYC-gated deposit pipeline, headless.
8
+ *
9
+ * This is the state machine kasu-ui and kasu-mobile each hand-wrote and then
10
+ * had to keep in step by hand: sign an auth message, generate the loan
11
+ * agreement, park while the lender reads it, sign it, approve the EXACT amount,
12
+ * fetch the KYC signature, submit, wait. Two implementations of one money path
13
+ * is one too many, so it lives here once and each application drives it from
14
+ * its own UI.
15
+ *
16
+ * **No React, no copy, no I/O of its own.** Every side effect is an injected
17
+ * port and every observable state is a code — `{ step: 'approve', reason:
18
+ * 'cancelled' }`, never "USDC approval was cancelled in your wallet". The
19
+ * applications keep their own `DEPOSIT_STEP_ERRORS` tables and map the codes to
20
+ * their words, in their design system and their language. Nothing in this file
21
+ * may be shown to a lender.
22
+ *
23
+ * ## Order, and why each step is where it is
24
+ *
25
+ * 1. **Allowance pre-check** — before anything is signed, because it decides
26
+ * `approvalRequired`, which decides `stepTotal`. A badge that said "3 of 4"
27
+ * and then silently became "3 of 3" would be describing a pipeline the
28
+ * lender is not in. A failed read assumes an approve IS needed: the safe
29
+ * default is a redundant approval, never a reverted deposit.
30
+ * 2. **`generating-sign`** — the lender signs the auth message
31
+ * (`buildLoanAgreementSignMessage`, or the legacy builder). kasu-backend
32
+ * reconstructs that string byte-for-byte to verify the signature.
33
+ * 3. **`generating-fetch`** — the agreements service returns the contract.
34
+ * 4. **`awaiting-accept`** — the run PARKS on a promise the consumer settles
35
+ * with `acceptContract()` or `declineContract()`. This is the only point at
36
+ * which a lender is committing to anything.
37
+ * 5. **`accepting-sign`** — the acceptance signature, which becomes the
38
+ * on-chain `depositData` via `encodeDepositData`.
39
+ * 6. **The 5-minute TTL guard** — checked AFTER the accept, because that is
40
+ * where the idling happens. An expired agreement is refused here rather than
41
+ * broadcast as a transaction that cannot succeed.
42
+ * 7. **`approve`** — the EXACT amount, never `MaxUint256`. House rule, and it
43
+ * is why the allowance drops to zero after every deposit and why step 1
44
+ * reads it fresh rather than trusting a cache.
45
+ * 8. **`request-sign` / `request-confirm`** — KYC signature, then the deposit,
46
+ * then the receipt.
47
+ *
48
+ * ## Failure codes
49
+ *
50
+ * A wallet rejection (`isUserRejected`) is `'cancelled'` — the lender changed
51
+ * their mind, and telling them something broke would be a lie. Only a WALLET
52
+ * call is ever classified that way: the HTTP ports are always `'failed'`,
53
+ * because a backend that words a refusal "declined" did not involve the
54
+ * lender's wallet. A reverted gas estimate on the request step
55
+ * (`isUnpredictableGas`) is `'insufficient-balance'` — nothing was refused, the
56
+ * transaction simply cannot succeed as composed. Everything else is `'failed'`
57
+ * and carries the original error for the consumer's crash reporter.
58
+ *
59
+ * ```ts
60
+ * const flow = new DepositFlow(ports);
61
+ * const stop = flow.subscribe((s) => render(s));
62
+ * await flow.start({ poolId, trancheId, amount, userAddress, ... });
63
+ * // …the consumer shows `flow.state.contract` and calls:
64
+ * await flow.acceptContract();
65
+ * ```
66
+ */
67
+ /**
68
+ * Where the run is. `success`, `declined` and `error` are terminal; everything
69
+ * else is in flight.
70
+ */
71
+ export type DepositPhase = 'idle' | 'generating-sign' | 'generating-fetch' | 'awaiting-accept' | 'accepting-sign' | 'approve' | 'request-sign' | 'request-confirm' | 'success' | 'declined' | 'error';
72
+ /**
73
+ * The four steps a lender sees as a badge. `approve` drops out of the sequence
74
+ * when the allowance already covers the deposit, which is why `stepIndex` and
75
+ * `stepTotal` are published rather than derived by each consumer.
76
+ */
77
+ export type DepositStep = 'generate' | 'confirm' | 'approve' | 'request';
78
+ /**
79
+ * Why a run did not reach `success`, as a code plus the step it happened on.
80
+ *
81
+ * The consumer maps this to its own words. `error` carries the underlying
82
+ * throw for a crash reporter — a `cancelled` and a `contract-expired` do not,
83
+ * because neither is a fault worth reporting.
84
+ */
85
+ export type DepositFailure = {
86
+ step: DepositStep;
87
+ reason: 'cancelled';
88
+ } | {
89
+ step: DepositStep;
90
+ reason: 'failed';
91
+ error: unknown;
92
+ } | {
93
+ step: 'request';
94
+ reason: 'insufficient-balance';
95
+ error: unknown;
96
+ } | {
97
+ step: 'request';
98
+ reason: 'contract-expired';
99
+ };
100
+ export type { WaitableTransaction };
101
+ /** What the KYC signing service hands back. */
102
+ export interface KycSignature {
103
+ signature: string;
104
+ blockExpiration: number | string;
105
+ }
106
+ /**
107
+ * The `/contract/generate` body, assembled by the flow and posted by the
108
+ * consumer's own port — through its server-side proxy (kasu-ui) or straight to
109
+ * the agreements service (kasu-mobile). The SDK never makes the call itself and
110
+ * never learns the URL or the key.
111
+ */
112
+ export interface GenerateContractRequest {
113
+ /**
114
+ * The lender's address, LOWERCASED. The legacy message embeds this casing
115
+ * and kasu-backend rebuilds the string from the body, so the two must
116
+ * agree.
117
+ */
118
+ address: string;
119
+ /** Signature over `signedMessage`. */
120
+ signature: string;
121
+ /** ms-epoch. The same value `signedMessage` states — do not re-clock it. */
122
+ timestamp: number;
123
+ /**
124
+ * The exact text that was signed. Sent so a consumer can log or assert on
125
+ * it; the backend rebuilds it from the other fields rather than trusting
126
+ * this one.
127
+ */
128
+ signedMessage: string;
129
+ poolId: string;
130
+ trancheId: string;
131
+ /** `'0'` for a variable-rate deposit. */
132
+ fixedTermConfigId: string;
133
+ /**
134
+ * The deposit in DISPLAY units, forwarded verbatim from
135
+ * `DepositFlowInput.depositAmount`. kasu-backend cross-checks it against
136
+ * the leading number of `amountLabel`.
137
+ */
138
+ depositAmount?: number;
139
+ /** The four human-readable fields, present only on the new format. */
140
+ strategyName?: string;
141
+ region?: string;
142
+ optionName?: string;
143
+ amountLabel?: string;
144
+ }
145
+ /**
146
+ * The human-readable `/contract/generate` format (BD deck slide 19): the lender
147
+ * signs a statement naming the strategy, region, option and amount.
148
+ *
149
+ * `amountLabel` must be derived from the same value as `depositAmount` — the
150
+ * backend refuses a message that states an amount other than the one being
151
+ * executed. The SDK does not format it, because formatting is the
152
+ * application's (and its locale's) business.
153
+ */
154
+ export interface LoanAgreementRequest {
155
+ format: 'loan-agreement';
156
+ strategyName: string;
157
+ region: string;
158
+ optionName: string;
159
+ amountLabel: string;
160
+ }
161
+ /**
162
+ * The legacy `I request contract content for {address} at {timestamp}.`
163
+ * format, which kasu-backend still accepts and `/contract/resolve` has no
164
+ * alternative to.
165
+ */
166
+ export interface LegacyContractRequest {
167
+ format: 'legacy';
168
+ }
169
+ export type ContractMessageRequest = LoanAgreementRequest | LegacyContractRequest;
170
+ /**
171
+ * Every side effect the pipeline needs, injected.
172
+ *
173
+ * `kasu.flows.deposit()` fills `readAllowance`, `approve`, `deposit` and
174
+ * `buildKycParams` from the SDK's own signer-bound implementations; the three
175
+ * that reach the consumer's own backend or wallet have no sensible default and
176
+ * are always supplied by the application.
177
+ */
178
+ export interface DepositPorts {
179
+ /** EIP-191 personal sign. Rejects when the lender refuses. */
180
+ signMessage(message: string): Promise<string>;
181
+ /** POST the generate request; resolve with the agreements service's reply. */
182
+ generateContract(req: GenerateContractRequest): Promise<GenerateContractResponse>;
183
+ /** Build the Nexera KYC params. Defaults to `kasu.deposits.buildKycParams`. */
184
+ buildKycParams(userAddress: `0x${string}`): KycParams | Promise<KycParams>;
185
+ /** Exchange those params for a signature at the consumer's own backend. */
186
+ getKycSignature(params: KycParams): Promise<KycSignature>;
187
+ /** ERC-20 `allowance(owner, spender)`, in base units. */
188
+ readAllowance(owner: string, spender: string): Promise<BigNumber>;
189
+ /** ERC-20 `approve(spender, amount)`. The flow only ever passes the EXACT amount. */
190
+ approve(spender: string, amount: BigNumber): Promise<WaitableTransaction>;
191
+ /** `requestDepositWithKyc`. Defaults to `kasu.deposits.deposit`. */
192
+ deposit(params: DepositParams): Promise<WaitableTransaction>;
193
+ /** ms-epoch clock. Defaults to `Date.now`; injected so the TTL is testable. */
194
+ now?(): number;
195
+ }
196
+ /** Construction options. `kasu.flows.deposit()` fills `spender` in. */
197
+ export interface DepositFlowOptions {
198
+ /** Agreement validity window; defaults to `CONTRACT_TTL_MS`. */
199
+ contractTtlMs?: number;
200
+ /**
201
+ * The ERC-20 spender every run approves and deposits through, when the
202
+ * input does not name one. `kasu.flows.deposit()` passes this chain's
203
+ * `contracts.LendingPoolManager`, which is the only contract the default
204
+ * deposit port calls.
205
+ */
206
+ spender?: string;
207
+ }
208
+ export interface DepositFlowInput {
209
+ poolId: string;
210
+ trancheId: string;
211
+ /** The deposit in BASE units (6dp for USDC and AUDD). */
212
+ amount: BigNumber;
213
+ /** `'0'` for a variable-rate deposit. */
214
+ fixedTermConfigId: string;
215
+ userAddress: `0x${string}`;
216
+ /**
217
+ * The ERC-20 spender, when it is NOT this chain's `LendingPoolManager`.
218
+ *
219
+ * Leave it out: `kasu.flows.deposit()` defaults it from the chain config,
220
+ * and the default deposit port calls no other contract. It exists for a
221
+ * consumer that replaced the `deposit` port with one that spends
222
+ * somewhere else — a wrong spender is an approval granted to the wrong
223
+ * contract and then a revert diagnosed as `insufficient-balance`.
224
+ */
225
+ spender?: string;
226
+ /** Which signed-message format to use, and its fields. */
227
+ contractMessage: ContractMessageRequest;
228
+ /**
229
+ * The deposit in DISPLAY units, for the generate request only.
230
+ *
231
+ * NOT derived from `amount`: turning base units back into a display number
232
+ * is formatting, and formatting is the application's job — it is also the
233
+ * application that produced `amountLabel`, and kasu-backend refuses the two
234
+ * if they disagree. Pass the same value both were built from.
235
+ */
236
+ depositAmount?: number;
237
+ }
238
+ export interface DepositState {
239
+ phase: DepositPhase;
240
+ /** The step `phase` belongs to; `null` only while idle. */
241
+ step: DepositStep | null;
242
+ /** 1-based badge position of `step`; `0` while idle. */
243
+ stepIndex: number;
244
+ /** `4`, or `3` when the allowance already covers the deposit. */
245
+ stepTotal: number;
246
+ /** Whether the approve step is in scope for this run. */
247
+ approvalRequired: boolean;
248
+ /** The generated agreement, from `generating-fetch` onwards. */
249
+ contract: GenerateContractResponse | null;
250
+ /** Set with `phase: 'error'`, cleared by `reset()`. */
251
+ failure: DepositFailure | null;
252
+ }
253
+ /** Generated agreements are valid for five minutes upstream. */
254
+ export declare const CONTRACT_TTL_MS: number;
255
+ /** What a run without a spender, from either source, fails with. */
256
+ export declare const NO_SPENDER_MESSAGE = "DepositFlow: no ERC-20 spender; build the flow with kasu.flows.deposit() or pass `spender` on the input";
257
+ export declare class DepositFlow extends Flow<DepositState, DepositFlowInput> {
258
+ private readonly _ports;
259
+ private readonly _ttlMs;
260
+ private readonly _defaultSpender;
261
+ private readonly _now;
262
+ /**
263
+ * The accept handshake. The run parks on this promise; `acceptContract`,
264
+ * `declineContract` and `reset` each settle it with an `AcceptOutcome`.
265
+ * Cleared the moment it settles so a stale resolver from an abandoned run
266
+ * can never leak into the next one.
267
+ */
268
+ private _accept;
269
+ /**
270
+ * The run token that is between `acceptContract()` and the wallet
271
+ * settling, or `null`.
272
+ *
273
+ * A token rather than a boolean, because the flag has to belong to the RUN
274
+ * that set it: after `reset()` out of a wallet prompt that never answers,
275
+ * the abandoned run's `finally` may not arrive for minutes, and a boolean
276
+ * left standing refuses both Accept and Decline on every run after it.
277
+ * A stale token simply is not the current generation.
278
+ */
279
+ private _acceptingFor;
280
+ constructor(_ports: DepositPorts, opts?: DepositFlowOptions);
281
+ /**
282
+ * Sign the agreement and resume the parked run. A no-op when nothing is
283
+ * parked, so a double tap cannot sign twice.
284
+ */
285
+ acceptContract(): Promise<void>;
286
+ /**
287
+ * Back out of the agreement. The run ends on `declined` — a legitimate
288
+ * choice, not a failure, and `state.failure` stays null.
289
+ *
290
+ * Ignored once `acceptContract()` has opened the wallet: an agreement in
291
+ * the middle of being signed cannot also be refused. `reset()` is the way
292
+ * out of a prompt that never answers.
293
+ */
294
+ declineContract(): void;
295
+ /** True only while THIS generation is waiting on the acceptance signature. */
296
+ private _isAccepting;
297
+ /** `reset()`: unpark the abandoned run and drop its handshake. */
298
+ protected _onAbandon(): void;
299
+ protected _run(input: DepositFlowInput, token: number): Promise<void>;
300
+ private _fail;
301
+ }
@@ -0,0 +1,358 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { asContractType, buildLegacyContractRequestMessage, buildLoanAgreementSignMessage, encodeDepositData, } from '../domain/loan-contract';
11
+ import { classifyWalletFailure, isUnpredictableGas, } from '../domain/wallet-errors';
12
+ import { Flow } from './flow';
13
+ /** Generated agreements are valid for five minutes upstream. */
14
+ export const CONTRACT_TTL_MS = 5 * 60 * 1000;
15
+ /** What a run without a spender, from either source, fails with. */
16
+ export const NO_SPENDER_MESSAGE = 'DepositFlow: no ERC-20 spender; build the flow with kasu.flows.deposit() or pass `spender` on the input';
17
+ const INITIAL = {
18
+ phase: 'idle',
19
+ step: null,
20
+ stepIndex: 0,
21
+ stepTotal: 4,
22
+ approvalRequired: true,
23
+ contract: null,
24
+ failure: null,
25
+ };
26
+ /** 1-based badge position, with `approve` dropped when it is out of scope. */
27
+ function stepIndexOf(step, approvalRequired) {
28
+ const order = approvalRequired
29
+ ? ['generate', 'confirm', 'approve', 'request']
30
+ : ['generate', 'confirm', 'request'];
31
+ return order.indexOf(step) + 1;
32
+ }
33
+ function badgeFor(step, approvalRequired) {
34
+ return {
35
+ step,
36
+ stepIndex: stepIndexOf(step, approvalRequired),
37
+ stepTotal: approvalRequired ? 4 : 3,
38
+ };
39
+ }
40
+ /**
41
+ * The request step has a third outcome. `UNPREDICTABLE_GAS_LIMIT` here is
42
+ * almost always `transferFrom` reverting on a balance that cannot cover the
43
+ * deposit, and it takes precedence: nothing was refused by the lender, so
44
+ * inviting a retry would just reproduce it.
45
+ */
46
+ function classifyRequest(err) {
47
+ if (isUnpredictableGas(err)) {
48
+ return { step: 'request', reason: 'insufficient-balance', error: err };
49
+ }
50
+ return classifyWalletFailure('request', err);
51
+ }
52
+ // ---------------------------------------------------------------------------
53
+ // The flow
54
+ // ---------------------------------------------------------------------------
55
+ export class DepositFlow extends Flow {
56
+ constructor(_ports, opts) {
57
+ var _a;
58
+ super(INITIAL);
59
+ this._ports = _ports;
60
+ /**
61
+ * The accept handshake. The run parks on this promise; `acceptContract`,
62
+ * `declineContract` and `reset` each settle it with an `AcceptOutcome`.
63
+ * Cleared the moment it settles so a stale resolver from an abandoned run
64
+ * can never leak into the next one.
65
+ */
66
+ this._accept = null;
67
+ /**
68
+ * The run token that is between `acceptContract()` and the wallet
69
+ * settling, or `null`.
70
+ *
71
+ * A token rather than a boolean, because the flag has to belong to the RUN
72
+ * that set it: after `reset()` out of a wallet prompt that never answers,
73
+ * the abandoned run's `finally` may not arrive for minutes, and a boolean
74
+ * left standing refuses both Accept and Decline on every run after it.
75
+ * A stale token simply is not the current generation.
76
+ */
77
+ this._acceptingFor = null;
78
+ this._ttlMs = (_a = opts === null || opts === void 0 ? void 0 : opts.contractTtlMs) !== null && _a !== void 0 ? _a : CONTRACT_TTL_MS;
79
+ this._defaultSpender = opts === null || opts === void 0 ? void 0 : opts.spender;
80
+ // Called through the ports object, never captured off it: a consumer
81
+ // whose clock is a method on its own object keeps its `this`.
82
+ this._now = () => { var _a, _b; return (_b = (_a = _ports.now) === null || _a === void 0 ? void 0 : _a.call(_ports)) !== null && _b !== void 0 ? _b : Date.now(); };
83
+ }
84
+ /**
85
+ * Sign the agreement and resume the parked run. A no-op when nothing is
86
+ * parked, so a double tap cannot sign twice.
87
+ */
88
+ acceptContract() {
89
+ return __awaiter(this, void 0, void 0, function* () {
90
+ const bridge = this._accept;
91
+ const contract = this._store.state.contract;
92
+ if (!bridge || !contract || this._isAccepting())
93
+ return;
94
+ const token = this._store.generation;
95
+ this._acceptingFor = token;
96
+ this._store.patch(Object.assign({ phase: 'accepting-sign' }, badgeFor('confirm', this._store.state.approvalRequired)), token);
97
+ try {
98
+ const signature = yield this._ports.signMessage(contract.contractMessage);
99
+ bridge.settle({ kind: 'accepted', signature });
100
+ }
101
+ catch (err) {
102
+ // A WALLET error, and the only one this flow classifies as a
103
+ // possible cancellation on the confirm step.
104
+ bridge.settle({ kind: 'failed', error: err });
105
+ }
106
+ finally {
107
+ // Only if this run still holds it: a `reset()` during the prompt
108
+ // may have started another one, and that one's flag is its own.
109
+ if (this._acceptingFor === token)
110
+ this._acceptingFor = null;
111
+ }
112
+ });
113
+ }
114
+ /**
115
+ * Back out of the agreement. The run ends on `declined` — a legitimate
116
+ * choice, not a failure, and `state.failure` stays null.
117
+ *
118
+ * Ignored once `acceptContract()` has opened the wallet: an agreement in
119
+ * the middle of being signed cannot also be refused. `reset()` is the way
120
+ * out of a prompt that never answers.
121
+ */
122
+ declineContract() {
123
+ const bridge = this._accept;
124
+ if (!bridge || this._isAccepting())
125
+ return;
126
+ this._accept = null;
127
+ bridge.settle({ kind: 'declined' });
128
+ }
129
+ /** True only while THIS generation is waiting on the acceptance signature. */
130
+ _isAccepting() {
131
+ return (this._acceptingFor !== null &&
132
+ this._store.isCurrent(this._acceptingFor));
133
+ }
134
+ /** `reset()`: unpark the abandoned run and drop its handshake. */
135
+ _onAbandon() {
136
+ const bridge = this._accept;
137
+ this._accept = null;
138
+ this._acceptingFor = null;
139
+ bridge === null || bridge === void 0 ? void 0 : bridge.settle({ kind: 'abandoned' });
140
+ }
141
+ // -----------------------------------------------------------------------
142
+ _run(input, token) {
143
+ return __awaiter(this, void 0, void 0, function* () {
144
+ var _a;
145
+ this._accept = null;
146
+ this._acceptingFor = null;
147
+ const ports = this._ports;
148
+ const owner = input.userAddress.toLowerCase();
149
+ // 0. The spender, from the input or from the chain config the facade
150
+ // built this flow with. Without one there is nothing to read an
151
+ // allowance against and nothing to approve — and guessing would
152
+ // grant an approval to the wrong contract.
153
+ const spender = (_a = input.spender) !== null && _a !== void 0 ? _a : this._defaultSpender;
154
+ if (!spender) {
155
+ this._fail(token, true, {
156
+ step: 'generate',
157
+ reason: 'failed',
158
+ error: new Error(NO_SPENDER_MESSAGE),
159
+ });
160
+ return;
161
+ }
162
+ // 1. Allowance pre-check. Decides `approvalRequired` — and therefore
163
+ // the badge total — before the lender is shown a single step. Read
164
+ // live, never cached: an exact-amount approval is fully consumed by
165
+ // the deposit it paid for, so a stale allowance is exactly the value
166
+ // that would wrongly skip the approve and revert the deposit.
167
+ let approvalRequired = true;
168
+ try {
169
+ const allowance = yield ports.readAllowance(owner, spender);
170
+ approvalRequired = allowance.lt(input.amount);
171
+ }
172
+ catch (_b) {
173
+ // A read failure is not a reason to skip an approval. Assume one is
174
+ // needed: the cost is a redundant approve, the alternative is a
175
+ // reverted deposit.
176
+ approvalRequired = true;
177
+ }
178
+ if (!this._store.isCurrent(token))
179
+ return;
180
+ // 2. Generate — sign the auth message.
181
+ this._store.patch(Object.assign({ approvalRequired, phase: 'generating-sign' }, badgeFor('generate', approvalRequired)), token);
182
+ const timestamp = this._now();
183
+ const signedMessage = buildAuthMessage(input, owner, timestamp);
184
+ let signature;
185
+ try {
186
+ signature = yield ports.signMessage(signedMessage);
187
+ }
188
+ catch (err) {
189
+ this._fail(token, approvalRequired, classifyWalletFailure('generate', err));
190
+ return;
191
+ }
192
+ if (!this._store.isCurrent(token))
193
+ return;
194
+ // 3. Generate — POST the request.
195
+ this._store.patch(Object.assign({ phase: 'generating-fetch' }, badgeFor('generate', approvalRequired)), token);
196
+ let contract;
197
+ try {
198
+ contract = yield ports.generateContract(Object.assign({ address: owner, signature,
199
+ timestamp,
200
+ signedMessage, poolId: input.poolId, trancheId: input.trancheId, fixedTermConfigId: input.fixedTermConfigId, depositAmount: input.depositAmount }, displayFieldsOf(input.contractMessage)));
201
+ }
202
+ catch (err) {
203
+ // Never a wallet rejection: this step is an HTTP call, and the
204
+ // lender's wallet was not involved in it. A backend that happened
205
+ // to echo the words "user rejected" must not be reported to them as
206
+ // something they did.
207
+ this._fail(token, approvalRequired, {
208
+ step: 'generate',
209
+ reason: 'failed',
210
+ error: err,
211
+ });
212
+ return;
213
+ }
214
+ if (!this._store.isCurrent(token))
215
+ return;
216
+ // 4. Park on the agreement until the consumer accepts or declines.
217
+ const outcome = yield new Promise((resolve) => {
218
+ this._accept = { settle: resolve };
219
+ this._store.patch(Object.assign({ phase: 'awaiting-accept', contract }, badgeFor('confirm', approvalRequired)), token);
220
+ });
221
+ this._accept = null;
222
+ // An abandoned run lands here too — `reset()` unparks it. The token
223
+ // check is what tells the two apart.
224
+ if (!this._store.isCurrent(token))
225
+ return;
226
+ if (outcome.kind === 'declined') {
227
+ this._store.patch(Object.assign({ phase: 'declined' }, badgeFor('confirm', approvalRequired)), token);
228
+ return;
229
+ }
230
+ if (outcome.kind !== 'accepted') {
231
+ if (outcome.kind === 'failed') {
232
+ this._fail(token, approvalRequired, classifyWalletFailure('confirm', outcome.error));
233
+ }
234
+ return;
235
+ }
236
+ // 5. TTL guard. Checked here because this is where the idling happens:
237
+ // the lender has just spent as long as they wanted reading. An
238
+ // expired agreement is refused rather than broadcast — the on-chain
239
+ // call would revert, after a wallet prompt and a gas estimate, with
240
+ // nothing on screen explaining why.
241
+ if (this._now() > contract.timestamp + this._ttlMs) {
242
+ this._fail(token, approvalRequired, {
243
+ step: 'request',
244
+ reason: 'contract-expired',
245
+ });
246
+ return;
247
+ }
248
+ const depositData = encodeDepositData({
249
+ signature: outcome.signature,
250
+ timestamp: contract.timestamp,
251
+ contractVersion: contract.contractVersion,
252
+ contractType: asContractType(contract.contractType),
253
+ });
254
+ // 6. Approve — the EXACT amount, never `MaxUint256`. House rule: an
255
+ // unlimited allowance outlives the deposit it was granted for, and a
256
+ // later exploit of the spender would drain a wallet that has long
257
+ // since stopped lending.
258
+ if (approvalRequired) {
259
+ this._store.patch(Object.assign({ phase: 'approve' }, badgeFor('approve', approvalRequired)), token);
260
+ try {
261
+ const tx = yield ports.approve(spender, input.amount);
262
+ yield tx.wait();
263
+ }
264
+ catch (err) {
265
+ this._fail(token, approvalRequired, classifyWalletFailure('approve', err));
266
+ return;
267
+ }
268
+ if (!this._store.isCurrent(token))
269
+ return;
270
+ }
271
+ // 7. Request — KYC signature, then the deposit and its receipt.
272
+ this._store.patch(Object.assign({ phase: 'request-sign' }, badgeFor('request', approvalRequired)), token);
273
+ // The two KYC ports reach the consumer's own backend, so they fail the
274
+ // way the generate step does: `failed`, with the error kept. Running
275
+ // them through the rejection classifier would let a backend wording —
276
+ // "Declined", "request rejected" — end a run as "you cancelled in your
277
+ // wallet", with the real error discarded and nothing to report.
278
+ let kyc;
279
+ try {
280
+ const kycParams = yield ports.buildKycParams(owner);
281
+ kyc = yield ports.getKycSignature(kycParams);
282
+ }
283
+ catch (err) {
284
+ this._fail(token, approvalRequired, {
285
+ step: 'request',
286
+ reason: 'failed',
287
+ error: err,
288
+ });
289
+ return;
290
+ }
291
+ if (!this._store.isCurrent(token))
292
+ return;
293
+ try {
294
+ const tx = yield ports.deposit({
295
+ poolId: input.poolId,
296
+ trancheId: input.trancheId,
297
+ amount: input.amount,
298
+ kycSignature: {
299
+ blockExpiration: kyc.blockExpiration,
300
+ signature: kyc.signature,
301
+ },
302
+ depositData,
303
+ fixedTermConfigId: input.fixedTermConfigId,
304
+ });
305
+ this._store.patch(Object.assign({ phase: 'request-confirm' }, badgeFor('request', approvalRequired)), token);
306
+ yield tx.wait();
307
+ }
308
+ catch (err) {
309
+ this._fail(token, approvalRequired, classifyRequest(err));
310
+ return;
311
+ }
312
+ if (!this._store.isCurrent(token))
313
+ return;
314
+ this._store.patch(Object.assign({ phase: 'success' }, badgeFor('request', approvalRequired)), token);
315
+ });
316
+ }
317
+ _fail(token, approvalRequired, failure) {
318
+ this._store.patch(Object.assign({ phase: 'error', failure }, badgeFor(failure.step, approvalRequired)), token);
319
+ }
320
+ }
321
+ // ---------------------------------------------------------------------------
322
+ // Message building
323
+ // ---------------------------------------------------------------------------
324
+ /**
325
+ * The auth message, in whichever format the consumer asked for. Both builders
326
+ * are the byte-exact protocol strings from `domain/loan-contract` — the string
327
+ * signed here and the body posted from `_run` state the SAME timestamp and the
328
+ * SAME lowercased address, because kasu-backend rebuilds one from the other.
329
+ */
330
+ function buildAuthMessage(input, owner, timestamp) {
331
+ if (input.contractMessage.format === 'legacy') {
332
+ return buildLegacyContractRequestMessage(owner, timestamp);
333
+ }
334
+ const { strategyName, region, optionName, amountLabel } = input.contractMessage;
335
+ return buildLoanAgreementSignMessage({
336
+ strategyName,
337
+ region,
338
+ optionName,
339
+ amountLabel,
340
+ timestamp,
341
+ });
342
+ }
343
+ /**
344
+ * The four display fields, present only on the new format. The backend picks
345
+ * its verification path on their presence: all four → the human-readable
346
+ * format, any missing → the legacy string.
347
+ */
348
+ function displayFieldsOf(message) {
349
+ if (message.format === 'legacy')
350
+ return {};
351
+ return {
352
+ strategyName: message.strategyName,
353
+ region: message.region,
354
+ optionName: message.optionName,
355
+ amountLabel: message.amountLabel,
356
+ };
357
+ }
358
+ //# sourceMappingURL=deposit-flow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deposit-flow.js","sourceRoot":"","sources":["../../src/flows/deposit-flow.ts"],"names":[],"mappings":"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"}