@kasufinance/kasu-sdk 2.6.0 → 2.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/README.md +167 -4
  2. package/dist/bundle.cjs.js +1389 -257
  3. package/dist/bundle.esm.js +1375 -258
  4. package/dist/domain/index.d.ts +5 -2
  5. package/dist/domain/index.js +3 -2
  6. package/dist/domain/index.js.map +1 -1
  7. package/dist/domain/requests.d.ts +42 -4
  8. package/dist/domain/requests.js +20 -4
  9. package/dist/domain/requests.js.map +1 -1
  10. package/dist/domain/revert-errors.d.ts +59 -0
  11. package/dist/domain/revert-errors.js +190 -0
  12. package/dist/domain/revert-errors.js.map +1 -0
  13. package/dist/domain/wallet-errors.d.ts +63 -8
  14. package/dist/domain/wallet-errors.js +115 -16
  15. package/dist/domain/wallet-errors.js.map +1 -1
  16. package/dist/facade/deposits.js +2 -1
  17. package/dist/facade/deposits.js.map +1 -1
  18. package/dist/facade/flows.d.ts +95 -0
  19. package/dist/facade/flows.js +116 -0
  20. package/dist/facade/flows.js.map +1 -0
  21. package/dist/facade/index.d.ts +3 -0
  22. package/dist/facade/index.js +3 -0
  23. package/dist/facade/index.js.map +1 -1
  24. package/dist/facade/kasu.d.ts +6 -2
  25. package/dist/facade/kasu.js +28 -3
  26. package/dist/facade/kasu.js.map +1 -1
  27. package/dist/facade/read-only.d.ts +12 -0
  28. package/dist/facade/read-only.js +13 -0
  29. package/dist/facade/read-only.js.map +1 -0
  30. package/dist/flows/deposit-flow.d.ts +332 -0
  31. package/dist/flows/deposit-flow.js +436 -0
  32. package/dist/flows/deposit-flow.js.map +1 -0
  33. package/dist/flows/flow.d.ts +72 -0
  34. package/dist/flows/flow.js +110 -0
  35. package/dist/flows/flow.js.map +1 -0
  36. package/dist/flows/index.d.ts +19 -0
  37. package/dist/flows/index.js +17 -0
  38. package/dist/flows/index.js.map +1 -0
  39. package/dist/flows/observable.d.ts +59 -0
  40. package/dist/flows/observable.js +81 -0
  41. package/dist/flows/observable.js.map +1 -0
  42. package/dist/flows/withdraw-flow.d.ts +99 -0
  43. package/dist/flows/withdraw-flow.js +83 -0
  44. package/dist/flows/withdraw-flow.js.map +1 -0
  45. package/dist/index.d.ts +1 -0
  46. package/dist/index.js +6 -0
  47. package/dist/index.js.map +1 -1
  48. package/dist/services/DataService/data-service.js +0 -1
  49. package/dist/services/DataService/data-service.js.map +1 -1
  50. package/package.json +8 -2
  51. package/src/domain/index.ts +10 -1
  52. package/src/domain/requests.ts +57 -4
  53. package/src/domain/revert-errors.ts +248 -0
  54. package/src/domain/wallet-errors.ts +135 -18
  55. package/src/facade/deposits.ts +2 -3
  56. package/src/facade/flows.ts +172 -0
  57. package/src/facade/index.ts +8 -0
  58. package/src/facade/kasu.ts +43 -3
  59. package/src/facade/read-only.ts +13 -0
  60. package/src/flows/deposit-flow.ts +884 -0
  61. package/src/flows/flow.ts +108 -0
  62. package/src/flows/index.ts +47 -0
  63. package/src/flows/observable.ts +97 -0
  64. package/src/flows/withdraw-flow.ts +210 -0
  65. package/src/index.ts +7 -0
  66. package/src/services/DataService/data-service.ts +0 -1
  67. package/dist/domain/au-minimum.test.d.ts +0 -1
  68. package/dist/domain/au-minimum.test.js +0 -202
  69. package/dist/domain/au-minimum.test.js.map +0 -1
  70. package/dist/domain/deposit-bounds.test.d.ts +0 -1
  71. package/dist/domain/deposit-bounds.test.js +0 -135
  72. package/dist/domain/deposit-bounds.test.js.map +0 -1
  73. package/dist/domain/loan-contract.test.d.ts +0 -1
  74. package/dist/domain/loan-contract.test.js +0 -255
  75. package/dist/domain/loan-contract.test.js.map +0 -1
  76. package/dist/domain/partners.test.d.ts +0 -1
  77. package/dist/domain/partners.test.js +0 -53
  78. package/dist/domain/partners.test.js.map +0 -1
  79. package/dist/domain/pools.test.d.ts +0 -1
  80. package/dist/domain/pools.test.js +0 -184
  81. package/dist/domain/pools.test.js.map +0 -1
  82. package/dist/domain/rates.test.d.ts +0 -1
  83. package/dist/domain/rates.test.js +0 -181
  84. package/dist/domain/rates.test.js.map +0 -1
  85. package/dist/domain/requests.test.d.ts +0 -1
  86. package/dist/domain/requests.test.js +0 -470
  87. package/dist/domain/requests.test.js.map +0 -1
  88. package/dist/domain/settlement.test.d.ts +0 -1
  89. package/dist/domain/settlement.test.js +0 -152
  90. package/dist/domain/settlement.test.js.map +0 -1
  91. package/dist/domain/tranche-display-name.test.d.ts +0 -1
  92. package/dist/domain/tranche-display-name.test.js +0 -58
  93. package/dist/domain/tranche-display-name.test.js.map +0 -1
  94. package/dist/domain/tranches.test.d.ts +0 -1
  95. package/dist/domain/tranches.test.js +0 -206
  96. package/dist/domain/tranches.test.js.map +0 -1
  97. package/dist/domain/wallet-errors.test.d.ts +0 -1
  98. package/dist/domain/wallet-errors.test.js +0 -71
  99. package/dist/domain/wallet-errors.test.js.map +0 -1
  100. package/dist/facade/config.test.d.ts +0 -1
  101. package/dist/facade/config.test.js +0 -216
  102. package/dist/facade/config.test.js.map +0 -1
  103. package/dist/facade/facade.test.d.ts +0 -1
  104. package/dist/facade/facade.test.js +0 -278
  105. package/dist/facade/facade.test.js.map +0 -1
  106. package/dist/services/Locking/calculate-apy.test.d.ts +0 -1
  107. package/dist/services/Locking/calculate-apy.test.js +0 -41
  108. package/dist/services/Locking/calculate-apy.test.js.map +0 -1
  109. package/dist/tests/sample.test.d.ts +0 -1
  110. package/dist/tests/sample.test.js +0 -59
  111. package/dist/tests/sample.test.js.map +0 -1
  112. package/src/domain/au-minimum.test.ts +0 -371
  113. package/src/domain/deposit-bounds.test.ts +0 -200
  114. package/src/domain/loan-contract.test.ts +0 -343
  115. package/src/domain/partners.test.ts +0 -83
  116. package/src/domain/pools.test.ts +0 -260
  117. package/src/domain/rates.test.ts +0 -254
  118. package/src/domain/requests.test.ts +0 -653
  119. package/src/domain/settlement.test.ts +0 -198
  120. package/src/domain/tranche-display-name.test.ts +0 -96
  121. package/src/domain/tranches.test.ts +0 -300
  122. package/src/domain/wallet-errors.test.ts +0 -100
  123. package/src/facade/config.test.ts +0 -265
  124. package/src/facade/facade.test.ts +0 -374
  125. package/src/services/Locking/calculate-apy.test.ts +0 -52
  126. package/src/tests/sample.test.ts +0 -63
@@ -0,0 +1,436 @@
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 { utils } from 'ethers';
11
+ import { asContractType, buildLegacyContractRequestMessage, buildLoanAgreementSignMessage, encodeDepositData, } from '../domain/loan-contract';
12
+ import { decodeRevert } from '../domain/revert-errors';
13
+ import { classifyWalletFailure, isUnpredictableGas, } from '../domain/wallet-errors';
14
+ import { Flow } from './flow';
15
+ /** Generated agreements are valid for five minutes upstream. */
16
+ export const CONTRACT_TTL_MS = 5 * 60 * 1000;
17
+ /** What a run without a spender, from either source, fails with. */
18
+ export const NO_SPENDER_MESSAGE = 'DepositFlow: no ERC-20 spender; build the flow with kasu.flows.deposit() or pass `spender` on the input';
19
+ /** What a malformed auth signature fails the generate step with. */
20
+ export const INVALID_AUTH_SIGNATURE_MESSAGE = 'DepositFlow: the wallet returned a malformed authentication signature; expected 65 bytes of 0x-prefixed hex';
21
+ /** What a malformed acceptance signature fails the confirm step with. */
22
+ export const INVALID_ACCEPTANCE_SIGNATURE_MESSAGE = 'DepositFlow: the wallet returned a malformed acceptance signature; expected 65 bytes of 0x-prefixed hex';
23
+ /**
24
+ * Is this an EIP-191 personal sign, in the only shape the protocol accepts?
25
+ *
26
+ * 65 bytes — `r`, `s`, `v` — 0x-prefixed. Nothing downstream checks it: the
27
+ * ABI coder takes any even-length hex as `bytes`, so `'0x'` and a 64-byte
28
+ * string both encode happily into a `depositData` the agreements service then
29
+ * cannot verify against anything. The check has to happen where the signature
30
+ * is taken, which is here.
31
+ */
32
+ function isPersonalSignature(signature) {
33
+ return utils.isHexString(signature, 65);
34
+ }
35
+ const INITIAL = {
36
+ phase: 'idle',
37
+ step: null,
38
+ stepIndex: 0,
39
+ stepTotal: 4,
40
+ approvalRequired: true,
41
+ contract: null,
42
+ failure: null,
43
+ };
44
+ /** 1-based badge position, with `approve` dropped when it is out of scope. */
45
+ function stepIndexOf(step, approvalRequired) {
46
+ const order = approvalRequired
47
+ ? ['generate', 'confirm', 'approve', 'request']
48
+ : ['generate', 'confirm', 'request'];
49
+ return order.indexOf(step) + 1;
50
+ }
51
+ function badgeFor(step, approvalRequired) {
52
+ return {
53
+ step,
54
+ stepIndex: stepIndexOf(step, approvalRequired),
55
+ stepTotal: approvalRequired ? 4 : 3,
56
+ };
57
+ }
58
+ /**
59
+ * The request step's extra outcomes, in the order the evidence supports.
60
+ *
61
+ * A revert is read for WHAT reverted before it is read as a shortfall.
62
+ * `requestDepositWithKyc` reverts for a whole family of declared reasons —
63
+ * `LendingPoolIsStopped`, `ClearingIsPending`, `UserNotKycd`, `UserBlocked`,
64
+ * `UserNotInAllowList`, `InvalidTranche`, `BlockExpired` — and every one of
65
+ * them used to arrive as `insufficient-balance`, which told a fully funded
66
+ * lender to top up a wallet that was never short while their pool was simply
67
+ * mid-clearing. So: a decoded protocol error is `reverted` and names itself.
68
+ *
69
+ * Only a token balance or allowance failure — or revert data nothing can
70
+ * decode, on the `UNPREDICTABLE_GAS_LIMIT` ethers raises for a failed gas
71
+ * estimate — is still `insufficient-balance`, which is the case that reason
72
+ * was named for and the one where topping up is genuinely the answer.
73
+ */
74
+ function classifyRequest(err) {
75
+ const revert = decodeRevert(err);
76
+ if ((revert === null || revert === void 0 ? void 0 : revert.family) === 'protocol') {
77
+ return {
78
+ step: 'request',
79
+ reason: 'reverted',
80
+ revertError: revert.name,
81
+ error: err,
82
+ };
83
+ }
84
+ if (revert !== null || isUnpredictableGas(err)) {
85
+ return { step: 'request', reason: 'insufficient-balance', error: err };
86
+ }
87
+ return classifyWalletFailure('request', err);
88
+ }
89
+ // ---------------------------------------------------------------------------
90
+ // The flow
91
+ // ---------------------------------------------------------------------------
92
+ export class DepositFlow extends Flow {
93
+ constructor(_ports, opts) {
94
+ var _a;
95
+ super(INITIAL);
96
+ this._ports = _ports;
97
+ /**
98
+ * The accept handshake. The run parks on this promise; `acceptContract`,
99
+ * `declineContract` and `reset` each settle it with an `AcceptOutcome`.
100
+ * Cleared the moment it settles so a stale resolver from an abandoned run
101
+ * can never leak into the next one.
102
+ */
103
+ this._accept = null;
104
+ /**
105
+ * The run token that is between `acceptContract()` and the wallet
106
+ * settling, or `null`.
107
+ *
108
+ * A token rather than a boolean, because the flag has to belong to the RUN
109
+ * that set it: after `reset()` out of a wallet prompt that never answers,
110
+ * the abandoned run's `finally` may not arrive for minutes, and a boolean
111
+ * left standing refuses both Accept and Decline on every run after it.
112
+ * A stale token simply is not the current generation.
113
+ */
114
+ this._acceptingFor = null;
115
+ this._ttlMs = (_a = opts === null || opts === void 0 ? void 0 : opts.contractTtlMs) !== null && _a !== void 0 ? _a : CONTRACT_TTL_MS;
116
+ this._defaultSpender = opts === null || opts === void 0 ? void 0 : opts.spender;
117
+ // Called through the ports object, never captured off it: a consumer
118
+ // whose clock is a method on its own object keeps its `this`.
119
+ 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(); };
120
+ }
121
+ /**
122
+ * Sign the agreement and resume the parked run. A no-op when nothing is
123
+ * parked, so a double tap cannot sign twice.
124
+ */
125
+ acceptContract() {
126
+ return __awaiter(this, void 0, void 0, function* () {
127
+ const bridge = this._accept;
128
+ const contract = this._store.state.contract;
129
+ if (!bridge || !contract || this._isAccepting())
130
+ return;
131
+ const token = this._store.generation;
132
+ this._acceptingFor = token;
133
+ this._store.patch(Object.assign({ phase: 'accepting-sign' }, badgeFor('confirm', this._store.state.approvalRequired)), token);
134
+ try {
135
+ const signature = yield this._ports.signMessage(contract.contractMessage);
136
+ // Checked HERE, not at the encoder: this is the signature the
137
+ // agreements service verifies the deposit against, and a wallet
138
+ // that returned something other than 65 bytes has not signed
139
+ // anything. Failing the confirm step names the step that produced
140
+ // it; letting it through would put an unverifiable blob on chain.
141
+ if (!isPersonalSignature(signature)) {
142
+ bridge.settle({
143
+ kind: 'failed',
144
+ error: new Error(INVALID_ACCEPTANCE_SIGNATURE_MESSAGE),
145
+ });
146
+ return;
147
+ }
148
+ bridge.settle({ kind: 'accepted', signature });
149
+ }
150
+ catch (err) {
151
+ // A WALLET error, and the only one this flow classifies as a
152
+ // possible cancellation on the confirm step.
153
+ bridge.settle({ kind: 'failed', error: err });
154
+ }
155
+ finally {
156
+ // Only if this run still holds it: a `reset()` during the prompt
157
+ // may have started another one, and that one's flag is its own.
158
+ if (this._acceptingFor === token)
159
+ this._acceptingFor = null;
160
+ }
161
+ });
162
+ }
163
+ /**
164
+ * Back out of the agreement. The run ends on `declined` — a legitimate
165
+ * choice, not a failure, and `state.failure` stays null.
166
+ *
167
+ * Ignored once `acceptContract()` has opened the wallet: an agreement in
168
+ * the middle of being signed cannot also be refused. `reset()` is the way
169
+ * out of a prompt that never answers.
170
+ */
171
+ declineContract() {
172
+ const bridge = this._accept;
173
+ if (!bridge || this._isAccepting())
174
+ return;
175
+ this._accept = null;
176
+ bridge.settle({ kind: 'declined' });
177
+ }
178
+ /** True only while THIS generation is waiting on the acceptance signature. */
179
+ _isAccepting() {
180
+ return (this._acceptingFor !== null &&
181
+ this._store.isCurrent(this._acceptingFor));
182
+ }
183
+ /** `reset()`: unpark the abandoned run and drop its handshake. */
184
+ _onAbandon() {
185
+ const bridge = this._accept;
186
+ this._accept = null;
187
+ this._acceptingFor = null;
188
+ bridge === null || bridge === void 0 ? void 0 : bridge.settle({ kind: 'abandoned' });
189
+ }
190
+ // -----------------------------------------------------------------------
191
+ _run(input, token) {
192
+ return __awaiter(this, void 0, void 0, function* () {
193
+ var _a;
194
+ this._accept = null;
195
+ this._acceptingFor = null;
196
+ const ports = this._ports;
197
+ const owner = input.userAddress.toLowerCase();
198
+ // 0. The spender, from the input or from the chain config the facade
199
+ // built this flow with. Without one there is nothing to read an
200
+ // allowance against and nothing to approve — and guessing would
201
+ // grant an approval to the wrong contract.
202
+ const spender = (_a = input.spender) !== null && _a !== void 0 ? _a : this._defaultSpender;
203
+ if (!spender) {
204
+ this._fail(token, true, {
205
+ step: 'generate',
206
+ reason: 'failed',
207
+ error: new Error(NO_SPENDER_MESSAGE),
208
+ });
209
+ return;
210
+ }
211
+ // 1. Allowance pre-check. Decides `approvalRequired` — and therefore
212
+ // the badge total — before the lender is shown a single step. Read
213
+ // live, never cached: an exact-amount approval is fully consumed by
214
+ // the deposit it paid for, so a stale allowance is exactly the value
215
+ // that would wrongly skip the approve and revert the deposit.
216
+ let approvalRequired = true;
217
+ try {
218
+ const allowance = yield ports.readAllowance(owner, spender);
219
+ approvalRequired = allowance.lt(input.amount);
220
+ }
221
+ catch (_b) {
222
+ // A read failure is not a reason to skip an approval. Assume one is
223
+ // needed: the cost is a redundant approve, the alternative is a
224
+ // reverted deposit.
225
+ approvalRequired = true;
226
+ }
227
+ if (!this._store.isCurrent(token))
228
+ return;
229
+ // 2. Generate — sign the auth message.
230
+ this._store.patch(Object.assign({ approvalRequired, phase: 'generating-sign' }, badgeFor('generate', approvalRequired)), token);
231
+ const timestamp = this._now();
232
+ const signedMessage = buildAuthMessage(input, owner, timestamp);
233
+ let signature;
234
+ try {
235
+ signature = yield ports.signMessage(signedMessage);
236
+ }
237
+ catch (err) {
238
+ this._fail(token, approvalRequired, classifyWalletFailure('generate', err));
239
+ return;
240
+ }
241
+ // The same EIP-191 shape as the acceptance, and the same reason to
242
+ // check it: kasu-backend verifies this one to decide whether to issue
243
+ // an agreement at all, so a malformed signature is a 4xx that says
244
+ // nothing about which step produced it. Named here instead.
245
+ if (!isPersonalSignature(signature)) {
246
+ this._fail(token, approvalRequired, {
247
+ step: 'generate',
248
+ reason: 'failed',
249
+ error: new Error(INVALID_AUTH_SIGNATURE_MESSAGE),
250
+ });
251
+ return;
252
+ }
253
+ if (!this._store.isCurrent(token))
254
+ return;
255
+ // 3. Generate — POST the request.
256
+ this._store.patch(Object.assign({ phase: 'generating-fetch' }, badgeFor('generate', approvalRequired)), token);
257
+ let contract;
258
+ try {
259
+ contract = yield ports.generateContract(Object.assign({ address: owner, signature,
260
+ timestamp,
261
+ signedMessage, poolId: input.poolId, trancheId: input.trancheId, fixedTermConfigId: input.fixedTermConfigId, depositAmount: input.depositAmount }, displayFieldsOf(input.contractMessage)));
262
+ }
263
+ catch (err) {
264
+ // Never a wallet rejection: this step is an HTTP call, and the
265
+ // lender's wallet was not involved in it. A backend that happened
266
+ // to echo the words "user rejected" must not be reported to them as
267
+ // something they did.
268
+ this._fail(token, approvalRequired, {
269
+ step: 'generate',
270
+ reason: 'failed',
271
+ error: err,
272
+ });
273
+ return;
274
+ }
275
+ if (!this._store.isCurrent(token))
276
+ return;
277
+ // 4. Park on the agreement until the consumer accepts or declines.
278
+ const outcome = yield new Promise((resolve) => {
279
+ this._accept = { settle: resolve };
280
+ this._store.patch(Object.assign({ phase: 'awaiting-accept', contract }, badgeFor('confirm', approvalRequired)), token);
281
+ });
282
+ this._accept = null;
283
+ // An abandoned run lands here too — `reset()` unparks it. The token
284
+ // check is what tells the two apart.
285
+ if (!this._store.isCurrent(token))
286
+ return;
287
+ if (outcome.kind === 'declined') {
288
+ this._store.patch(Object.assign({ phase: 'declined' }, badgeFor('confirm', approvalRequired)), token);
289
+ return;
290
+ }
291
+ if (outcome.kind !== 'accepted') {
292
+ if (outcome.kind === 'failed') {
293
+ this._fail(token, approvalRequired, classifyWalletFailure('confirm', outcome.error));
294
+ }
295
+ return;
296
+ }
297
+ // 5. TTL guard. Checked here because this is where the idling happens:
298
+ // the lender has just spent as long as they wanted reading. An
299
+ // expired agreement is refused rather than broadcast — the on-chain
300
+ // call would revert, after a wallet prompt and a gas estimate, with
301
+ // nothing on screen explaining why.
302
+ if (this._now() > contract.timestamp + this._ttlMs) {
303
+ this._fail(token, approvalRequired, {
304
+ step: 'request',
305
+ reason: 'contract-expired',
306
+ });
307
+ return;
308
+ }
309
+ // The acceptance signature is already known to be 65 bytes, but the
310
+ // encoder also reads `timestamp`, `contractVersion` and
311
+ // `contractType` off a response the SDK did not produce. `start()`
312
+ // promises it does not reject, so anything that throws in here becomes
313
+ // a failure the consumer can render rather than an unhandled rejection
314
+ // in an application that was told it never had to catch one.
315
+ let depositData;
316
+ try {
317
+ depositData = encodeDepositData({
318
+ signature: outcome.signature,
319
+ timestamp: contract.timestamp,
320
+ contractVersion: contract.contractVersion,
321
+ contractType: asContractType(contract.contractType),
322
+ });
323
+ }
324
+ catch (err) {
325
+ this._fail(token, approvalRequired, {
326
+ step: 'request',
327
+ reason: 'failed',
328
+ error: err,
329
+ });
330
+ return;
331
+ }
332
+ // 6. Approve — the EXACT amount, never `MaxUint256`. House rule: an
333
+ // unlimited allowance outlives the deposit it was granted for, and a
334
+ // later exploit of the spender would drain a wallet that has long
335
+ // since stopped lending.
336
+ if (approvalRequired) {
337
+ this._store.patch(Object.assign({ phase: 'approve' }, badgeFor('approve', approvalRequired)), token);
338
+ try {
339
+ const tx = yield ports.approve(spender, input.amount);
340
+ yield tx.wait();
341
+ }
342
+ catch (err) {
343
+ this._fail(token, approvalRequired, classifyWalletFailure('approve', err));
344
+ return;
345
+ }
346
+ if (!this._store.isCurrent(token))
347
+ return;
348
+ }
349
+ // 7. Request — KYC signature, then the deposit and its receipt.
350
+ this._store.patch(Object.assign({ phase: 'request-sign' }, badgeFor('request', approvalRequired)), token);
351
+ // The two KYC ports reach the consumer's own backend, so they fail the
352
+ // way the generate step does: `failed`, with the error kept. Running
353
+ // them through the rejection classifier would let a backend wording —
354
+ // "Declined", "request rejected" — end a run as "you cancelled in your
355
+ // wallet", with the real error discarded and nothing to report.
356
+ let kyc;
357
+ try {
358
+ const kycParams = yield ports.buildKycParams(owner);
359
+ kyc = yield ports.getKycSignature(kycParams);
360
+ }
361
+ catch (err) {
362
+ this._fail(token, approvalRequired, {
363
+ step: 'request',
364
+ reason: 'failed',
365
+ error: err,
366
+ });
367
+ return;
368
+ }
369
+ if (!this._store.isCurrent(token))
370
+ return;
371
+ try {
372
+ const tx = yield ports.deposit({
373
+ poolId: input.poolId,
374
+ trancheId: input.trancheId,
375
+ amount: input.amount,
376
+ kycSignature: {
377
+ blockExpiration: kyc.blockExpiration,
378
+ signature: kyc.signature,
379
+ },
380
+ depositData,
381
+ fixedTermConfigId: input.fixedTermConfigId,
382
+ });
383
+ this._store.patch(Object.assign({ phase: 'request-confirm' }, badgeFor('request', approvalRequired)), token);
384
+ yield tx.wait();
385
+ }
386
+ catch (err) {
387
+ this._fail(token, approvalRequired, classifyRequest(err));
388
+ return;
389
+ }
390
+ if (!this._store.isCurrent(token))
391
+ return;
392
+ this._store.patch(Object.assign({ phase: 'success' }, badgeFor('request', approvalRequired)), token);
393
+ });
394
+ }
395
+ _fail(token, approvalRequired, failure) {
396
+ this._store.patch(Object.assign({ phase: 'error', failure }, badgeFor(failure.step, approvalRequired)), token);
397
+ }
398
+ }
399
+ // ---------------------------------------------------------------------------
400
+ // Message building
401
+ // ---------------------------------------------------------------------------
402
+ /**
403
+ * The auth message, in whichever format the consumer asked for. Both builders
404
+ * are the byte-exact protocol strings from `domain/loan-contract` — the string
405
+ * signed here and the body posted from `_run` state the SAME timestamp and the
406
+ * SAME lowercased address, because kasu-backend rebuilds one from the other.
407
+ */
408
+ function buildAuthMessage(input, owner, timestamp) {
409
+ if (input.contractMessage.format === 'legacy') {
410
+ return buildLegacyContractRequestMessage(owner, timestamp);
411
+ }
412
+ const { strategyName, region, optionName, amountLabel } = input.contractMessage;
413
+ return buildLoanAgreementSignMessage({
414
+ strategyName,
415
+ region,
416
+ optionName,
417
+ amountLabel,
418
+ timestamp,
419
+ });
420
+ }
421
+ /**
422
+ * The four display fields, present only on the new format. The backend picks
423
+ * its verification path on their presence: all four → the human-readable
424
+ * format, any missing → the legacy string.
425
+ */
426
+ function displayFieldsOf(message) {
427
+ if (message.format === 'legacy')
428
+ return {};
429
+ return {
430
+ strategyName: message.strategyName,
431
+ region: message.region,
432
+ optionName: message.optionName,
433
+ amountLabel: message.amountLabel,
434
+ };
435
+ }
436
+ //# 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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"}
@@ -0,0 +1,72 @@
1
+ import { FlowStore } from './observable';
2
+ /**
3
+ * The run lifecycle both flows share: one run at a time, every transition
4
+ * published, and a `reset()` that is safe to call in the middle of one.
5
+ *
6
+ * `DepositFlow` and `WithdrawFlow` each carried their own copy of this — the
7
+ * re-entrancy guard, the `try/finally` around the run, `state`, `isRunning`,
8
+ * `subscribe`, `reset`. Two copies of a guard is two places for a guard to be
9
+ * wrong, on the money path, which is the same reason the pipelines themselves
10
+ * moved out of the applications.
11
+ *
12
+ * ## The guard and the run token are separate, and both matter
13
+ *
14
+ * `_runToken` is the re-entrancy guard: claimed synchronously, before the
15
+ * first `await`, so a double tap cannot launch two pipelines. The store's
16
+ * `generation` is the abandonment mechanism: an in-flight run holds the value
17
+ * it claimed, and every `patch` and `isCurrent` checkpoint it makes after
18
+ * `reset()` is dropped.
19
+ *
20
+ * `reset()` releases the guard IMMEDIATELY rather than waiting for the
21
+ * abandoned run to notice. It has to: a run parked on a wallet prompt that
22
+ * never answers is a promise that may never settle, and a consumer that has
23
+ * left that screen must be able to start a new run in the same tick. The
24
+ * abandoned run's `finally` therefore releases the guard only if it still
25
+ * holds it — by then a NEW run may own it, and clearing it there would let a
26
+ * third run start alongside the second.
27
+ */
28
+ export declare abstract class Flow<S, I> {
29
+ protected readonly _store: FlowStore<S>;
30
+ /**
31
+ * The token of the run currently holding the guard, or `null` when none
32
+ * does. Not a boolean: releasing the guard has to be attributable to the
33
+ * run that claimed it.
34
+ */
35
+ private _runToken;
36
+ protected constructor(initial: S);
37
+ /** The current state. Every transition is also published to `subscribe`. */
38
+ get state(): S;
39
+ /** True while a run is in flight, including while parked. */
40
+ get isRunning(): boolean;
41
+ /**
42
+ * Observe every transition. Returns the unsubscribe function.
43
+ *
44
+ * The listener is not called on subscribe; read `state` for the value it
45
+ * starts from.
46
+ */
47
+ subscribe(listener: (state: S) => void): () => void;
48
+ /**
49
+ * Run the pipeline. Resolves when it reaches a terminal phase — it does
50
+ * not reject, because every outcome a consumer can act on is in `state`.
51
+ *
52
+ * A second call while one is in flight is a no-op: one submission per
53
+ * intent, however many times the button is pressed.
54
+ */
55
+ start(input: I): Promise<void>;
56
+ /**
57
+ * Back to `idle`, abandoning any run in flight: its remaining transitions
58
+ * are dropped, whatever it is parked on is unparked, and the guard is
59
+ * released at once so `start()` is accepted in the SAME tick. Subscribers
60
+ * are kept — the consumer watching the last run is the one watching the
61
+ * next.
62
+ */
63
+ reset(): void;
64
+ /**
65
+ * Hook for a flow that parks: unpark it. Called by `reset()` after the
66
+ * generation has been bumped, so anything the abandoned run does with the
67
+ * result is dropped.
68
+ */
69
+ protected _onAbandon(): void;
70
+ /** The pipeline itself. `token` is this run's; check it after every await. */
71
+ protected abstract _run(input: I, token: number): Promise<void>;
72
+ }
@@ -0,0 +1,110 @@
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 { FlowStore } from './observable';
11
+ /**
12
+ * The run lifecycle both flows share: one run at a time, every transition
13
+ * published, and a `reset()` that is safe to call in the middle of one.
14
+ *
15
+ * `DepositFlow` and `WithdrawFlow` each carried their own copy of this — the
16
+ * re-entrancy guard, the `try/finally` around the run, `state`, `isRunning`,
17
+ * `subscribe`, `reset`. Two copies of a guard is two places for a guard to be
18
+ * wrong, on the money path, which is the same reason the pipelines themselves
19
+ * moved out of the applications.
20
+ *
21
+ * ## The guard and the run token are separate, and both matter
22
+ *
23
+ * `_runToken` is the re-entrancy guard: claimed synchronously, before the
24
+ * first `await`, so a double tap cannot launch two pipelines. The store's
25
+ * `generation` is the abandonment mechanism: an in-flight run holds the value
26
+ * it claimed, and every `patch` and `isCurrent` checkpoint it makes after
27
+ * `reset()` is dropped.
28
+ *
29
+ * `reset()` releases the guard IMMEDIATELY rather than waiting for the
30
+ * abandoned run to notice. It has to: a run parked on a wallet prompt that
31
+ * never answers is a promise that may never settle, and a consumer that has
32
+ * left that screen must be able to start a new run in the same tick. The
33
+ * abandoned run's `finally` therefore releases the guard only if it still
34
+ * holds it — by then a NEW run may own it, and clearing it there would let a
35
+ * third run start alongside the second.
36
+ */
37
+ export class Flow {
38
+ constructor(initial) {
39
+ /**
40
+ * The token of the run currently holding the guard, or `null` when none
41
+ * does. Not a boolean: releasing the guard has to be attributable to the
42
+ * run that claimed it.
43
+ */
44
+ this._runToken = null;
45
+ this._store = new FlowStore(initial);
46
+ }
47
+ /** The current state. Every transition is also published to `subscribe`. */
48
+ get state() {
49
+ return this._store.state;
50
+ }
51
+ /** True while a run is in flight, including while parked. */
52
+ get isRunning() {
53
+ return this._runToken !== null;
54
+ }
55
+ /**
56
+ * Observe every transition. Returns the unsubscribe function.
57
+ *
58
+ * The listener is not called on subscribe; read `state` for the value it
59
+ * starts from.
60
+ */
61
+ subscribe(listener) {
62
+ return this._store.subscribe(listener);
63
+ }
64
+ /**
65
+ * Run the pipeline. Resolves when it reaches a terminal phase — it does
66
+ * not reject, because every outcome a consumer can act on is in `state`.
67
+ *
68
+ * A second call while one is in flight is a no-op: one submission per
69
+ * intent, however many times the button is pressed.
70
+ */
71
+ start(input) {
72
+ return __awaiter(this, void 0, void 0, function* () {
73
+ if (this._runToken !== null)
74
+ return;
75
+ this._store.reset();
76
+ const token = this._store.beginRun();
77
+ this._runToken = token;
78
+ try {
79
+ yield this._run(input, token);
80
+ }
81
+ finally {
82
+ if (this._runToken === token)
83
+ this._runToken = null;
84
+ }
85
+ });
86
+ }
87
+ /**
88
+ * Back to `idle`, abandoning any run in flight: its remaining transitions
89
+ * are dropped, whatever it is parked on is unparked, and the guard is
90
+ * released at once so `start()` is accepted in the SAME tick. Subscribers
91
+ * are kept — the consumer watching the last run is the one watching the
92
+ * next.
93
+ */
94
+ reset() {
95
+ this._runToken = null;
96
+ // Bump the generation BEFORE unparking, so the abandoned run's next
97
+ // checkpoint already reads as superseded.
98
+ this._store.reset();
99
+ this._onAbandon();
100
+ }
101
+ /**
102
+ * Hook for a flow that parks: unpark it. Called by `reset()` after the
103
+ * generation has been bumped, so anything the abandoned run does with the
104
+ * result is dropped.
105
+ */
106
+ _onAbandon() {
107
+ // A flow with nothing parked has nothing to unpark.
108
+ }
109
+ }
110
+ //# sourceMappingURL=flow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flow.js","sourceRoot":"","sources":["../../src/flows/flow.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,OAAgB,IAAI;IAUtB,YAAsB,OAAU;QAPhC;;;;WAIG;QACK,cAAS,GAAkB,IAAI,CAAC;QAGpC,IAAI,CAAC,MAAM,GAAG,IAAI,SAAS,CAAI,OAAO,CAAC,CAAC;IAC5C,CAAC;IAED,4EAA4E;IAC5E,IAAI,KAAK;QACL,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;IAC7B,CAAC;IAED,6DAA6D;IAC7D,IAAI,SAAS;QACT,OAAO,IAAI,CAAC,SAAS,KAAK,IAAI,CAAC;IACnC,CAAC;IAED;;;;;OAKG;IACH,SAAS,CAAC,QAA4B;QAClC,OAAO,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IAC3C,CAAC;IAED;;;;;;OAMG;IACG,KAAK,CAAC,KAAQ;;YAChB,IAAI,IAAI,CAAC,SAAS,KAAK,IAAI;gBAAE,OAAO;YACpC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YACpB,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;YACrC,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;YACvB,IAAI,CAAC;gBACD,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;YAClC,CAAC;oBAAS,CAAC;gBACP,IAAI,IAAI,CAAC,SAAS,KAAK,KAAK;oBAAE,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;YACxD,CAAC;QACL,CAAC;KAAA;IAED;;;;;;OAMG;IACH,KAAK;QACD,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,oEAAoE;QACpE,0CAA0C;QAC1C,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QACpB,IAAI,CAAC,UAAU,EAAE,CAAC;IACtB,CAAC;IAED;;;;OAIG;IACO,UAAU;QAChB,oDAAoD;IACxD,CAAC;CAIJ"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Flows: the headless money-path state machines.
3
+ *
4
+ * `domain/` holds rules that are pure functions. These are the same idea one
5
+ * level up — a rule that unfolds over time, with side effects the consumer
6
+ * injects as ports. They own the ORDER of a deposit and a withdrawal, the
7
+ * guards around them, and the codes that describe where a run got to. They own
8
+ * no UI, no framework, no network and no words.
9
+ *
10
+ * Every application drove its own copy of the deposit pipeline before this, and
11
+ * the copies had already started to differ.
12
+ */
13
+ export { Flow } from './flow';
14
+ export { FlowStore } from './observable';
15
+ export type { WaitableTransaction } from './observable';
16
+ export { CONTRACT_TTL_MS, DepositFlow, INVALID_ACCEPTANCE_SIGNATURE_MESSAGE, INVALID_AUTH_SIGNATURE_MESSAGE, NO_SPENDER_MESSAGE, } from './deposit-flow';
17
+ export type { ContractMessageRequest, DepositFailure, DepositFlowInput, DepositFlowOptions, DepositPhase, DepositPorts, DepositState, DepositStep, GenerateContractRequest, KycSignature, LegacyContractRequest, LoanAgreementRequest, } from './deposit-flow';
18
+ export { NO_KYC_PARAMS_MESSAGE, WithdrawFlow } from './withdraw-flow';
19
+ export type { WithdrawFailure, WithdrawFlowInput, WithdrawPhase, WithdrawPorts, WithdrawState, WithdrawStep, } from './withdraw-flow';