@kasufinance/kasu-sdk 2.6.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 (122) hide show
  1. package/README.md +128 -3
  2. package/dist/bundle.cjs.js +1119 -254
  3. package/dist/bundle.esm.js +1109 -255
  4. package/dist/domain/index.d.ts +3 -2
  5. package/dist/domain/index.js +2 -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/wallet-errors.d.ts +63 -8
  11. package/dist/domain/wallet-errors.js +115 -16
  12. package/dist/domain/wallet-errors.js.map +1 -1
  13. package/dist/facade/deposits.js +2 -1
  14. package/dist/facade/deposits.js.map +1 -1
  15. package/dist/facade/flows.d.ts +95 -0
  16. package/dist/facade/flows.js +116 -0
  17. package/dist/facade/flows.js.map +1 -0
  18. package/dist/facade/index.d.ts +3 -0
  19. package/dist/facade/index.js +3 -0
  20. package/dist/facade/index.js.map +1 -1
  21. package/dist/facade/kasu.d.ts +6 -2
  22. package/dist/facade/kasu.js +28 -3
  23. package/dist/facade/kasu.js.map +1 -1
  24. package/dist/facade/read-only.d.ts +12 -0
  25. package/dist/facade/read-only.js +13 -0
  26. package/dist/facade/read-only.js.map +1 -0
  27. package/dist/flows/deposit-flow.d.ts +301 -0
  28. package/dist/flows/deposit-flow.js +358 -0
  29. package/dist/flows/deposit-flow.js.map +1 -0
  30. package/dist/flows/flow.d.ts +72 -0
  31. package/dist/flows/flow.js +110 -0
  32. package/dist/flows/flow.js.map +1 -0
  33. package/dist/flows/index.d.ts +19 -0
  34. package/dist/flows/index.js +17 -0
  35. package/dist/flows/index.js.map +1 -0
  36. package/dist/flows/observable.d.ts +59 -0
  37. package/dist/flows/observable.js +81 -0
  38. package/dist/flows/observable.js.map +1 -0
  39. package/dist/flows/withdraw-flow.d.ts +99 -0
  40. package/dist/flows/withdraw-flow.js +83 -0
  41. package/dist/flows/withdraw-flow.js.map +1 -0
  42. package/dist/index.d.ts +1 -0
  43. package/dist/index.js +6 -0
  44. package/dist/index.js.map +1 -1
  45. package/dist/services/DataService/data-service.js +0 -1
  46. package/dist/services/DataService/data-service.js.map +1 -1
  47. package/package.json +8 -2
  48. package/src/domain/index.ts +7 -1
  49. package/src/domain/requests.ts +57 -4
  50. package/src/domain/wallet-errors.ts +135 -18
  51. package/src/facade/deposits.ts +2 -3
  52. package/src/facade/flows.ts +172 -0
  53. package/src/facade/index.ts +8 -0
  54. package/src/facade/kasu.ts +43 -3
  55. package/src/facade/read-only.ts +13 -0
  56. package/src/flows/deposit-flow.ts +775 -0
  57. package/src/flows/flow.ts +108 -0
  58. package/src/flows/index.ts +45 -0
  59. package/src/flows/observable.ts +97 -0
  60. package/src/flows/withdraw-flow.ts +210 -0
  61. package/src/index.ts +7 -0
  62. package/src/services/DataService/data-service.ts +0 -1
  63. package/dist/domain/au-minimum.test.d.ts +0 -1
  64. package/dist/domain/au-minimum.test.js +0 -202
  65. package/dist/domain/au-minimum.test.js.map +0 -1
  66. package/dist/domain/deposit-bounds.test.d.ts +0 -1
  67. package/dist/domain/deposit-bounds.test.js +0 -135
  68. package/dist/domain/deposit-bounds.test.js.map +0 -1
  69. package/dist/domain/loan-contract.test.d.ts +0 -1
  70. package/dist/domain/loan-contract.test.js +0 -255
  71. package/dist/domain/loan-contract.test.js.map +0 -1
  72. package/dist/domain/partners.test.d.ts +0 -1
  73. package/dist/domain/partners.test.js +0 -53
  74. package/dist/domain/partners.test.js.map +0 -1
  75. package/dist/domain/pools.test.d.ts +0 -1
  76. package/dist/domain/pools.test.js +0 -184
  77. package/dist/domain/pools.test.js.map +0 -1
  78. package/dist/domain/rates.test.d.ts +0 -1
  79. package/dist/domain/rates.test.js +0 -181
  80. package/dist/domain/rates.test.js.map +0 -1
  81. package/dist/domain/requests.test.d.ts +0 -1
  82. package/dist/domain/requests.test.js +0 -470
  83. package/dist/domain/requests.test.js.map +0 -1
  84. package/dist/domain/settlement.test.d.ts +0 -1
  85. package/dist/domain/settlement.test.js +0 -152
  86. package/dist/domain/settlement.test.js.map +0 -1
  87. package/dist/domain/tranche-display-name.test.d.ts +0 -1
  88. package/dist/domain/tranche-display-name.test.js +0 -58
  89. package/dist/domain/tranche-display-name.test.js.map +0 -1
  90. package/dist/domain/tranches.test.d.ts +0 -1
  91. package/dist/domain/tranches.test.js +0 -206
  92. package/dist/domain/tranches.test.js.map +0 -1
  93. package/dist/domain/wallet-errors.test.d.ts +0 -1
  94. package/dist/domain/wallet-errors.test.js +0 -71
  95. package/dist/domain/wallet-errors.test.js.map +0 -1
  96. package/dist/facade/config.test.d.ts +0 -1
  97. package/dist/facade/config.test.js +0 -216
  98. package/dist/facade/config.test.js.map +0 -1
  99. package/dist/facade/facade.test.d.ts +0 -1
  100. package/dist/facade/facade.test.js +0 -278
  101. package/dist/facade/facade.test.js.map +0 -1
  102. package/dist/services/Locking/calculate-apy.test.d.ts +0 -1
  103. package/dist/services/Locking/calculate-apy.test.js +0 -41
  104. package/dist/services/Locking/calculate-apy.test.js.map +0 -1
  105. package/dist/tests/sample.test.d.ts +0 -1
  106. package/dist/tests/sample.test.js +0 -59
  107. package/dist/tests/sample.test.js.map +0 -1
  108. package/src/domain/au-minimum.test.ts +0 -371
  109. package/src/domain/deposit-bounds.test.ts +0 -200
  110. package/src/domain/loan-contract.test.ts +0 -343
  111. package/src/domain/partners.test.ts +0 -83
  112. package/src/domain/pools.test.ts +0 -260
  113. package/src/domain/rates.test.ts +0 -254
  114. package/src/domain/requests.test.ts +0 -653
  115. package/src/domain/settlement.test.ts +0 -198
  116. package/src/domain/tranche-display-name.test.ts +0 -96
  117. package/src/domain/tranches.test.ts +0 -300
  118. package/src/domain/wallet-errors.test.ts +0 -100
  119. package/src/facade/config.test.ts +0 -265
  120. package/src/facade/facade.test.ts +0 -374
  121. package/src/services/Locking/calculate-apy.test.ts +0 -52
  122. package/src/tests/sample.test.ts +0 -63
@@ -1,470 +0,0 @@
1
- import { UserRequestStatus } from '../services/UserLending/subgraph-types';
2
- import { countSubmissions, deriveRequestState, firstSubmissionTimestamp, isCycleClosed, submissionEvents, } from './requests';
3
- /**
4
- * Ported from kasu-ui `src/features/portfolio/lib/derive-transaction-view.test.ts`.
5
- * The status-word, detail-line, tranche-rename and `splitPoolName` cases stay
6
- * there — they assert copy and display, which this layer does not own. What
7
- * comes across is every assertion about codes, kind, amounts, ids and counts,
8
- * because those are the branch behaviour.
9
- */
10
- const TRANCHE_ID = '0xtranche-senior';
11
- const OTHER_TRANCHE_ID = '0xtranche-mezzanine';
12
- const POOL_ID = '0xPool-PayFi';
13
- const POOL_NAME = 'Payment Finance (PayFi) - Payment Clearing Houses';
14
- const REQUESTED = UserRequestStatus.REQUESTED;
15
- const PROCESSING = UserRequestStatus.PROCESSING;
16
- const PROCESSED = UserRequestStatus.PROCESSED;
17
- function makeRequest(overrides = {}) {
18
- return Object.assign({ id: 'req-1', userId: '0xuser', lendingPool: {
19
- id: POOL_ID,
20
- name: POOL_NAME,
21
- tranches: [{ orderId: '0' }],
22
- }, requestType: 'Deposit', trancheId: TRANCHE_ID, trancheName: 'Senior', requestedAmount: '100', acceptedAmount: '0', rejectedAmount: '0', timestamp: 1700000000, status: REQUESTED, canCancel: true, events: [], nftId: '', apy: '0', fixedTermConfig: undefined }, overrides);
23
- }
24
- function event(partial) {
25
- return Object.assign({ id: 'evt', requestType: 'Initiated', assetAmount: '0', totalRequested: '0', totalAccepted: '0', totalRejected: '0', index: 0, timestamp: 1700000000, transactionHash: '0x', trancheName: 'Senior', trancheId: TRANCHE_ID, apy: '0', epochId: '0' }, partial);
26
- }
27
- describe('deriveRequestState — every branch of the derivation', () => {
28
- it('deposit just submitted, cycle open → pending · inflow · +requested', () => {
29
- const state = deriveRequestState(makeRequest());
30
- expect(state.statusCode).toBe('pending');
31
- expect(state.kind).toBe('inflow');
32
- expect(state.amount).toBe(100);
33
- expect(state.cycleClosed).toBe(false);
34
- expect(state.canCancel).toBe(true);
35
- });
36
- it('deposit while its pool is clearing (canCancel false) → pending, cycle CLOSED', () => {
37
- const state = deriveRequestState(makeRequest({ canCancel: false }));
38
- expect(state.statusCode).toBe('pending');
39
- expect(state.cycleClosed).toBe(true);
40
- });
41
- it('a STICKY Processing raw status with an open cycle stays pending and open', () => {
42
- // The subgraph never resets `status` after a partial fill — `canCancel`
43
- // alone decides open/closed.
44
- const state = deriveRequestState(makeRequest({ status: PROCESSING, canCancel: true }));
45
- expect(state.statusCode).toBe('pending');
46
- expect(state.cycleClosed).toBe(false);
47
- expect(state.rawStatus).toBe(PROCESSING);
48
- });
49
- it('deposit fully accepted → complete · inflow · +accepted', () => {
50
- const state = deriveRequestState(makeRequest({
51
- status: PROCESSED,
52
- canCancel: false,
53
- acceptedAmount: '100',
54
- }));
55
- expect(state.statusCode).toBe('complete');
56
- expect(state.kind).toBe('inflow');
57
- expect(state.amount).toBe(100);
58
- });
59
- it('deposit partially accepted → partial · inflow · the accepted figure', () => {
60
- const state = deriveRequestState(makeRequest({
61
- status: PROCESSED,
62
- canCancel: false,
63
- acceptedAmount: '60',
64
- rejectedAmount: '40',
65
- }));
66
- expect(state.statusCode).toBe('partial');
67
- expect(state.kind).toBe('inflow');
68
- expect(state.amount).toBe(60);
69
- expect(state.requestedAmount).toBe(100);
70
- expect(state.acceptedAmount).toBe(60);
71
- });
72
- it('deposit fully rejected → rejected · neutral · 0 — a rejection IS a resolution', () => {
73
- const state = deriveRequestState(makeRequest({
74
- status: PROCESSED,
75
- canCancel: false,
76
- rejectedAmount: '100',
77
- }));
78
- expect(state.statusCode).toBe('rejected');
79
- expect(state.kind).toBe('neutral');
80
- expect(state.amount).toBe(0);
81
- });
82
- it('deposit cancelled → cancelled · neutral · 0', () => {
83
- const state = deriveRequestState(makeRequest({ events: [event({ requestType: 'Cancelled' })] }));
84
- expect(state.statusCode).toBe('cancelled');
85
- expect(state.kind).toBe('neutral');
86
- expect(state.amount).toBe(0);
87
- });
88
- it('a Cancelled event outranks a resolved status', () => {
89
- const state = deriveRequestState(makeRequest({
90
- status: PROCESSED,
91
- canCancel: false,
92
- acceptedAmount: '100',
93
- events: [event({ requestType: 'Cancelled' })],
94
- }));
95
- expect(state.statusCode).toBe('cancelled');
96
- expect(state.amount).toBe(0);
97
- });
98
- it('deposit reallocated (Accepted into another tranche) → reallocated · inflow', () => {
99
- const state = deriveRequestState(makeRequest({
100
- status: PROCESSED,
101
- canCancel: false,
102
- acceptedAmount: '100',
103
- events: [
104
- event({
105
- requestType: 'Accepted',
106
- trancheId: OTHER_TRANCHE_ID,
107
- trancheName: 'Mezzanine',
108
- assetAmount: '100',
109
- }),
110
- ],
111
- }));
112
- expect(state.statusCode).toBe('reallocated');
113
- expect(state.kind).toBe('inflow');
114
- expect(state.amount).toBe(100);
115
- });
116
- it('an Accepted event into the SAME tranche is not a reallocation', () => {
117
- const state = deriveRequestState(makeRequest({
118
- status: PROCESSED,
119
- canCancel: false,
120
- acceptedAmount: '100',
121
- events: [
122
- event({
123
- requestType: 'Accepted',
124
- trancheId: TRANCHE_ID.toUpperCase(),
125
- assetAmount: '100',
126
- }),
127
- ],
128
- }));
129
- // Tranche ids are compared case-insensitively, so an upper-cased
130
- // spelling of the same tranche must not read as a move.
131
- expect(state.statusCode).toBe('complete');
132
- });
133
- it('an explicit Reallocated event is a reallocation whatever the tranche', () => {
134
- const state = deriveRequestState(makeRequest({
135
- status: PROCESSED,
136
- canCancel: false,
137
- acceptedAmount: '100',
138
- events: [
139
- event({
140
- requestType: 'Reallocated',
141
- assetAmount: '100',
142
- }),
143
- ],
144
- }));
145
- expect(state.statusCode).toBe('reallocated');
146
- });
147
- it('a withdrawal is never reallocated, whatever its events say', () => {
148
- const state = deriveRequestState(makeRequest({
149
- requestType: 'Withdrawal',
150
- status: PROCESSED,
151
- canCancel: false,
152
- acceptedAmount: '100',
153
- events: [
154
- event({
155
- requestType: 'Accepted',
156
- trancheId: OTHER_TRANCHE_ID,
157
- assetAmount: '100',
158
- }),
159
- ],
160
- }));
161
- expect(state.statusCode).toBe('complete');
162
- expect(state.kind).toBe('outflow');
163
- });
164
- it('withdrawal submitted, cycle open → pending · outflow · −requested', () => {
165
- const state = deriveRequestState(makeRequest({ requestType: 'Withdrawal' }));
166
- expect(state.statusCode).toBe('pending');
167
- expect(state.kind).toBe('outflow');
168
- expect(state.amount).toBe(-100);
169
- });
170
- it('withdrawal fully filled → complete · −accepted', () => {
171
- const state = deriveRequestState(makeRequest({
172
- requestType: 'Withdrawal',
173
- status: PROCESSED,
174
- canCancel: false,
175
- acceptedAmount: '100',
176
- }));
177
- expect(state.statusCode).toBe('complete');
178
- expect(state.amount).toBe(-100);
179
- });
180
- it('withdrawal partly filled with a LIVE remainder → partial while the cycle is open', () => {
181
- // Realistic shape: the sticky raw status reads Processing, canCancel
182
- // marks the new cycle open — the request returns to the queue with a
183
- // live Cancel.
184
- const state = deriveRequestState(makeRequest({
185
- requestType: 'Withdrawal',
186
- status: PROCESSING,
187
- canCancel: true,
188
- acceptedAmount: '60',
189
- }));
190
- expect(state.statusCode).toBe('partial');
191
- expect(state.kind).toBe('outflow');
192
- expect(state.amount).toBe(-60);
193
- expect(state.cycleClosed).toBe(false);
194
- });
195
- it('withdrawal partly filled, pool CLEARING → pending with the cycle closed (locked remainder)', () => {
196
- const state = deriveRequestState(makeRequest({
197
- requestType: 'Withdrawal',
198
- status: PROCESSING,
199
- canCancel: false,
200
- acceptedAmount: '60',
201
- }));
202
- expect(state.statusCode).toBe('pending');
203
- expect(state.cycleClosed).toBe(true);
204
- expect(state.amount).toBe(-100);
205
- });
206
- it('withdrawal partly filled, TERMINAL → partial', () => {
207
- const state = deriveRequestState(makeRequest({
208
- requestType: 'Withdrawal',
209
- status: PROCESSED,
210
- canCancel: false,
211
- acceptedAmount: '60',
212
- }));
213
- expect(state.statusCode).toBe('partial');
214
- expect(state.amount).toBe(-60);
215
- });
216
- it('forced withdrawal → forced · outflow · −accepted', () => {
217
- const state = deriveRequestState(makeRequest({
218
- requestType: 'Withdrawal',
219
- status: PROCESSED,
220
- canCancel: false,
221
- acceptedAmount: '80',
222
- events: [event({ requestType: 'Forced' })],
223
- }));
224
- expect(state.statusCode).toBe('forced');
225
- expect(state.kind).toBe('outflow');
226
- expect(state.amount).toBe(-80);
227
- });
228
- it('a Forced event on a DEPOSIT is not a forced withdrawal', () => {
229
- const state = deriveRequestState(makeRequest({
230
- status: PROCESSED,
231
- canCancel: false,
232
- acceptedAmount: '80',
233
- events: [event({ requestType: 'Forced' })],
234
- }));
235
- expect(state.statusCode).toBe('complete');
236
- expect(state.kind).toBe('inflow');
237
- });
238
- it('withdrawal cancelled → cancelled · neutral · 0', () => {
239
- const state = deriveRequestState(makeRequest({
240
- requestType: 'Withdrawal',
241
- events: [event({ requestType: 'Cancelled' })],
242
- }));
243
- expect(state.statusCode).toBe('cancelled');
244
- expect(state.kind).toBe('neutral');
245
- expect(state.amount).toBe(0);
246
- });
247
- });
248
- describe('deriveRequestState — the cancelled-amount recovery', () => {
249
- it('recovers a zeroed requestedAmount from the Initiated event', () => {
250
- const state = deriveRequestState(makeRequest({
251
- requestedAmount: '0',
252
- events: [
253
- event({ requestType: 'Initiated', assetAmount: '250' }),
254
- event({ requestType: 'Cancelled', index: 1 }),
255
- ],
256
- }));
257
- expect(state.requestedAmount).toBe(250);
258
- expect(state.initiatedAmount).toBe(250);
259
- });
260
- it('falls back to 0 when the cancelled request has no Initiated event', () => {
261
- const state = deriveRequestState(makeRequest({
262
- requestedAmount: '0',
263
- events: [event({ requestType: 'Cancelled' })],
264
- }));
265
- expect(state.requestedAmount).toBe(0);
266
- expect(state.initiatedAmount).toBeNull();
267
- });
268
- it('does not recover for a request that was NOT cancelled', () => {
269
- // A live request with a genuinely zero requested amount keeps it; only
270
- // the cancelled branch reaches for the Initiated event.
271
- const state = deriveRequestState(makeRequest({
272
- requestedAmount: '0',
273
- events: [
274
- event({ requestType: 'Initiated', assetAmount: '250' }),
275
- ],
276
- }));
277
- expect(state.requestedAmount).toBe(0);
278
- expect(state.initiatedAmount).toBe(250);
279
- });
280
- });
281
- describe('deriveRequestState — ids, counts and pass-through fields', () => {
282
- it('takes contractId from the Initiated EVENT, not the request id', () => {
283
- const state = deriveRequestState(makeRequest({
284
- events: [
285
- event({ requestType: 'Initiated', id: 'req-1-0' }),
286
- event({
287
- requestType: 'Increased',
288
- id: 'req-1-1',
289
- index: 1,
290
- }),
291
- ],
292
- }));
293
- expect(state.contractId).toBe('req-1-0');
294
- expect(state.id).toBe('req-1');
295
- });
296
- it('leaves contractId empty when nothing was Initiated', () => {
297
- expect(deriveRequestState(makeRequest()).contractId).toBe('');
298
- });
299
- it('lowercases the pool id and leaves the pool name raw', () => {
300
- const state = deriveRequestState(makeRequest());
301
- expect(state.poolId).toBe(POOL_ID.toLowerCase());
302
- expect(state.poolName).toBe(POOL_NAME);
303
- });
304
- it('leaves the tranche name RAW — the display rename is the app’s', () => {
305
- // An Apxium pool: kasu-ui shows "Upper Mezzanine" here, this layer must
306
- // not, or a renamed name would reach matching code.
307
- const state = deriveRequestState(makeRequest({
308
- lendingPool: {
309
- id: '0xpool-apxium',
310
- name: 'Taxation Funding (Tax Pay) - Diversified Businesses',
311
- tranches: [{ orderId: '0' }],
312
- },
313
- }));
314
- expect(state.trancheName).toBe('Senior');
315
- });
316
- it('defaults fixedTermConfigId to "0" for a variable-rate request', () => {
317
- expect(deriveRequestState(makeRequest()).fixedTermConfigId).toBe('0');
318
- });
319
- it('passes a fixed-term configId through', () => {
320
- const state = deriveRequestState(makeRequest({
321
- fixedTermConfig: {
322
- configId: '7',
323
- apy: '0.1',
324
- epochLockDuration: '4',
325
- epochInterestRate: '0.002',
326
- },
327
- }));
328
- expect(state.fixedTermConfigId).toBe('7');
329
- });
330
- it('counts only submissions into submissionCount and takes the earliest one', () => {
331
- const state = deriveRequestState(makeRequest({
332
- events: [
333
- event({
334
- requestType: 'Initiated',
335
- timestamp: 1700000500,
336
- }),
337
- event({
338
- requestType: 'Increased',
339
- timestamp: 1700000100,
340
- index: 1,
341
- }),
342
- event({
343
- requestType: 'Accepted',
344
- timestamp: 1700000900,
345
- index: 2,
346
- }),
347
- ],
348
- }));
349
- expect(state.submissionCount).toBe(2);
350
- expect(state.firstSubmissionTimestamp).toBe(1700000100);
351
- });
352
- it('reports a null first-submission timestamp before the Initiated event indexes', () => {
353
- const state = deriveRequestState(makeRequest());
354
- expect(state.submissionCount).toBe(0);
355
- expect(state.firstSubmissionTimestamp).toBeNull();
356
- });
357
- it('keeps "the subgraph reported nothing" distinct from a reported zero', () => {
358
- expect(deriveRequestState(makeRequest()).acceptedAmount).toBe(0);
359
- expect(deriveRequestState(makeRequest({ acceptedAmount: '' }))
360
- .acceptedAmount).toBeNull();
361
- expect(deriveRequestState(makeRequest({
362
- acceptedAmount: undefined,
363
- })).acceptedAmount).toBeNull();
364
- });
365
- });
366
- /**
367
- * The transition rule: `cancelled` is reachable only from a Cancelled EVENT,
368
- * and every derivation lands on exactly one of the seven codes.
369
- */
370
- describe('deriveRequestState — permitted transitions', () => {
371
- const FIXTURES = [
372
- {},
373
- { canCancel: false },
374
- { status: PROCESSING, canCancel: true },
375
- { status: PROCESSED, canCancel: false, acceptedAmount: '100' },
376
- { status: PROCESSED, canCancel: false, rejectedAmount: '100' },
377
- {
378
- requestType: 'Withdrawal',
379
- status: PROCESSING,
380
- canCancel: true,
381
- acceptedAmount: '60',
382
- },
383
- {
384
- requestType: 'Withdrawal',
385
- status: PROCESSED,
386
- canCancel: false,
387
- acceptedAmount: '60',
388
- },
389
- { events: [event({ requestType: 'Cancelled' })] },
390
- ];
391
- const CODES = [
392
- 'pending',
393
- 'complete',
394
- 'partial',
395
- 'rejected',
396
- 'reallocated',
397
- 'cancelled',
398
- 'forced',
399
- ];
400
- it('every derivation lands on exactly one known code', () => {
401
- for (const overrides of FIXTURES) {
402
- expect(CODES).toContain(deriveRequestState(makeRequest(overrides)).statusCode);
403
- }
404
- });
405
- it('cancelled derives ONLY from a Cancelled event', () => {
406
- var _a;
407
- for (const overrides of FIXTURES) {
408
- const hasCancelEvent = ((_a = overrides.events) !== null && _a !== void 0 ? _a : []).some((e) => e.requestType === 'Cancelled');
409
- const state = deriveRequestState(makeRequest(overrides));
410
- expect(state.statusCode === 'cancelled').toBe(hasCancelEvent);
411
- }
412
- });
413
- it('the loan-agreement affordance follows from requestType + statusCode', () => {
414
- // kasu-ui's `canViewContract`, reconstructed from the two fields this
415
- // layer exposes: deposits have an agreement unless nothing was ever
416
- // issued (cancelled / fully rejected); withdrawals sign none.
417
- const canView = (s) => s.requestType === 'Deposit' &&
418
- s.statusCode !== 'cancelled' &&
419
- s.statusCode !== 'rejected';
420
- expect(canView(deriveRequestState(makeRequest()))).toBe(true);
421
- expect(canView(deriveRequestState(makeRequest({ events: [event({ requestType: 'Cancelled' })] })))).toBe(false);
422
- expect(canView(deriveRequestState(makeRequest({
423
- status: PROCESSED,
424
- canCancel: false,
425
- rejectedAmount: '100',
426
- })))).toBe(false);
427
- expect(canView(deriveRequestState(makeRequest({ requestType: 'Withdrawal' })))).toBe(false);
428
- });
429
- });
430
- describe('submissionEvents / countSubmissions', () => {
431
- const events = [
432
- event({ requestType: 'Initiated' }),
433
- event({ requestType: 'Accepted', index: 1 }),
434
- event({ requestType: 'Increased', index: 2 }),
435
- event({ requestType: 'Rejected', index: 3 }),
436
- event({ requestType: 'Cancelled', index: 4 }),
437
- event({ requestType: 'Reallocated', index: 5 }),
438
- event({ requestType: 'Forced', index: 6 }),
439
- ];
440
- it('keeps only Initiated + Increased, in input order', () => {
441
- expect(submissionEvents(events).map((e) => e.requestType)).toEqual([
442
- 'Initiated',
443
- 'Increased',
444
- ]);
445
- });
446
- it('counts them', () => {
447
- expect(countSubmissions(events)).toBe(2);
448
- expect(countSubmissions([])).toBe(0);
449
- });
450
- });
451
- describe('firstSubmissionTimestamp', () => {
452
- it('returns the earliest submission timestamp, ignoring outcome events', () => {
453
- expect(firstSubmissionTimestamp([
454
- event({ requestType: 'Initiated', timestamp: 300 }),
455
- event({ requestType: 'Increased', timestamp: 200 }),
456
- event({ requestType: 'Accepted', timestamp: 100 }),
457
- ], 999)).toBe(200);
458
- });
459
- it('falls back when the bundle carries no submission yet', () => {
460
- expect(firstSubmissionTimestamp([], 42)).toBe(42);
461
- expect(firstSubmissionTimestamp([event({ requestType: 'Accepted', timestamp: 1 })], 42)).toBe(42);
462
- });
463
- });
464
- describe('isCycleClosed', () => {
465
- it('is the inverse of the SDK per-pool cancel signal', () => {
466
- expect(isCycleClosed({ canCancel: true })).toBe(false);
467
- expect(isCycleClosed({ canCancel: false })).toBe(true);
468
- });
469
- });
470
- //# sourceMappingURL=requests.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"requests.test.js","sourceRoot":"","sources":["../../src/domain/requests.test.ts"],"names":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- export {};
@@ -1,152 +0,0 @@
1
- import { CLEARING_WINDOW_SECONDS, computeSettlementWindow, deriveCycleDates, nextCycleBoundary, } from './settlement';
2
- /**
3
- * Ported from kasu-ui `src/features/portfolio/lib/settlement-window.test.ts`
4
- * and the non-format half of
5
- * `src/features/lending/lib/cycle-dates.test.ts`. The `formatCycleDate` /
6
- * `formatCycleCloseUtc` cases stay there — they assert printed words.
7
- */
8
- const HOUR = 60 * 60;
9
- const DAY = 24 * HOUR;
10
- const CLEARING = 48 * HOUR;
11
- const WEEK = 7 * DAY;
12
- describe('computeSettlementWindow', () => {
13
- it('returns "unknown" when the epoch boundary is missing', () => {
14
- expect(computeSettlementWindow({
15
- nowSeconds: 1000000,
16
- nextEpochStart: 0,
17
- })).toEqual({ phase: 'unknown' });
18
- });
19
- it('returns "unknown" when the epoch boundary is stale (already elapsed)', () => {
20
- expect(computeSettlementWindow({
21
- nowSeconds: 1000000,
22
- nextEpochStart: 999000,
23
- })).toEqual({ phase: 'unknown' });
24
- });
25
- it('counts down to the clearing window when more than 48h from epoch end', () => {
26
- const epochEnd = 1700000000; // Thu 06:00 UTC
27
- const now = epochEnd - 3 * DAY; // 24h before the window opens
28
- const result = computeSettlementWindow({
29
- nowSeconds: now,
30
- nextEpochStart: epochEnd,
31
- });
32
- expect(result.phase).toBe('awaiting');
33
- if (result.phase !== 'awaiting')
34
- return;
35
- expect(result.nextClearingStart).toBe(epochEnd - CLEARING); // Tue 06:00
36
- expect(result.secondsUntilClearing).toBe(DAY);
37
- });
38
- it('reports "clearing" only inside the 48h window before epoch end', () => {
39
- const epochEnd = 1700000000;
40
- const now = epochEnd - 24 * HOUR; // 24h into the window
41
- const result = computeSettlementWindow({
42
- nowSeconds: now,
43
- nextEpochStart: epochEnd,
44
- });
45
- expect(result.phase).toBe('clearing');
46
- if (result.phase !== 'clearing')
47
- return;
48
- expect(result.epochEnd).toBe(epochEnd);
49
- expect(result.secondsUntilEpochEnd).toBe(24 * HOUR);
50
- });
51
- it('flips awaiting → clearing exactly at the window boundary (T-48h)', () => {
52
- const epochEnd = 1700000000;
53
- expect(computeSettlementWindow({
54
- nowSeconds: epochEnd - CLEARING - 1,
55
- nextEpochStart: epochEnd,
56
- }).phase).toBe('awaiting');
57
- expect(computeSettlementWindow({
58
- nowSeconds: epochEnd - CLEARING,
59
- nextEpochStart: epochEnd,
60
- }).phase).toBe('clearing');
61
- });
62
- it('respects a non-default clearing window length', () => {
63
- const epochEnd = 1700000000;
64
- const now = epochEnd - 36 * HOUR;
65
- // 36h out is "clearing" under the default 48h window but "awaiting"
66
- // under a 24h one.
67
- expect(computeSettlementWindow({
68
- nowSeconds: now,
69
- nextEpochStart: epochEnd,
70
- }).phase).toBe('clearing');
71
- expect(computeSettlementWindow({
72
- nowSeconds: now,
73
- nextEpochStart: epochEnd,
74
- clearingWindowSeconds: 24 * HOUR,
75
- }).phase).toBe('awaiting');
76
- });
77
- });
78
- describe('nextCycleBoundary', () => {
79
- const epochEnd = 1700000000;
80
- const clearingStart = epochEnd - CLEARING;
81
- it('returns the cycle close while the window is still ahead', () => {
82
- expect(nextCycleBoundary(epochEnd, epochEnd - 3 * DAY)).toBe(clearingStart);
83
- });
84
- it('returns the epoch end once inside the clearing window', () => {
85
- expect(nextCycleBoundary(epochEnd, clearingStart + 1)).toBe(epochEnd);
86
- });
87
- it('hands over from close to epoch end exactly at the boundary instant', () => {
88
- // At T-48h the close has just been reached, so the next thing to wait
89
- // for is the epoch end — not the instant we are standing on.
90
- expect(nextCycleBoundary(epochEnd, clearingStart - 1)).toBe(clearingStart);
91
- expect(nextCycleBoundary(epochEnd, clearingStart)).toBe(epochEnd);
92
- });
93
- it('returns undefined when there is nothing left to wait for', () => {
94
- expect(nextCycleBoundary(epochEnd, epochEnd)).toBeUndefined(); // elapsed
95
- expect(nextCycleBoundary(epochEnd, epochEnd + DAY)).toBeUndefined(); // stale
96
- expect(nextCycleBoundary(undefined, epochEnd - DAY)).toBeUndefined(); // not loaded
97
- expect(nextCycleBoundary(0, epochEnd - DAY)).toBeUndefined(); // sentinel zero
98
- });
99
- it('agrees with computeSettlementWindow about where the window opens', () => {
100
- // One number, two consumers: the phase machine and the timer helper
101
- // must never disagree about when the cycle turns.
102
- expect(CLEARING_WINDOW_SECONDS).toBe(CLEARING);
103
- const justInside = nextCycleBoundary(epochEnd, clearingStart);
104
- expect(computeSettlementWindow({
105
- nowSeconds: clearingStart,
106
- nextEpochStart: epochEnd,
107
- }).phase).toBe('clearing');
108
- expect(justInside).toBe(epochEnd);
109
- });
110
- it('respects a non-default clearing window length', () => {
111
- const now = epochEnd - 36 * HOUR;
112
- // 36h out: inside a 48h window (next stop is the epoch end), still
113
- // ahead of a 24h one (next stop is that window opening).
114
- expect(nextCycleBoundary(epochEnd, now)).toBe(epochEnd);
115
- expect(nextCycleBoundary(epochEnd, now, 24 * HOUR)).toBe(epochEnd - 24 * HOUR);
116
- });
117
- });
118
- describe('deriveCycleDates', () => {
119
- // Fixture: epoch end = Thu 6 Aug 2026, 06:00 UTC.
120
- const EPOCH_END = Date.UTC(2026, 7, 6, 6, 0, 0) / 1000; // 1785996000
121
- const CLOSE = EPOCH_END - CLEARING; // Tue 4 Aug 06:00 UTC
122
- it('returns close = epochEnd − 48h and outcome = epochEnd before the window opens', () => {
123
- const now = Date.UTC(2026, 7, 1, 12, 0, 0) / 1000; // Sat 1 Aug
124
- expect(deriveCycleDates(EPOCH_END, now)).toEqual({
125
- close: CLOSE,
126
- outcome: EPOCH_END,
127
- });
128
- });
129
- it('advances to the next weekly cycle when the request lands inside the clearing window', () => {
130
- // now is Wed 5 Aug 00:00 — inside [close, epochEnd): this cycle has
131
- // already closed, so the request queues for next week.
132
- const now = Date.UTC(2026, 7, 5, 0, 0, 0) / 1000;
133
- expect(deriveCycleDates(EPOCH_END, now)).toEqual({
134
- close: CLOSE + WEEK,
135
- outcome: EPOCH_END + WEEK,
136
- });
137
- });
138
- it('returns null when the epoch boundary is missing', () => {
139
- expect(deriveCycleDates(undefined, EPOCH_END - WEEK)).toBeNull();
140
- expect(deriveCycleDates(0, EPOCH_END - WEEK)).toBeNull();
141
- });
142
- it('returns null when the epoch boundary is stale (already elapsed)', () => {
143
- expect(deriveCycleDates(EPOCH_END, EPOCH_END + 60)).toBeNull();
144
- });
145
- it('runs on the same window constant as the phase machine', () => {
146
- var _a;
147
- const now = Date.UTC(2026, 7, 1, 12, 0, 0) / 1000;
148
- const dates = deriveCycleDates(EPOCH_END, now);
149
- expect(dates === null || dates === void 0 ? void 0 : dates.outcome).toBe(((_a = dates === null || dates === void 0 ? void 0 : dates.close) !== null && _a !== void 0 ? _a : 0) + CLEARING_WINDOW_SECONDS);
150
- });
151
- });
152
- //# sourceMappingURL=settlement.test.js.map