@kasufinance/kasu-sdk 2.5.0 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -5
- package/dist/bundle.cjs.js +797 -16
- package/dist/bundle.esm.js +771 -17
- package/dist/domain/au-minimum.d.ts +135 -0
- package/dist/domain/au-minimum.js +154 -0
- package/dist/domain/au-minimum.js.map +1 -0
- package/dist/domain/au-minimum.test.d.ts +1 -0
- package/dist/domain/au-minimum.test.js +202 -0
- package/dist/domain/au-minimum.test.js.map +1 -0
- package/dist/domain/index.d.ts +17 -3
- package/dist/domain/index.js +13 -3
- package/dist/domain/index.js.map +1 -1
- package/dist/domain/loan-contract.d.ts +174 -0
- package/dist/domain/loan-contract.js +160 -0
- package/dist/domain/loan-contract.js.map +1 -0
- package/dist/domain/loan-contract.test.d.ts +1 -0
- package/dist/domain/loan-contract.test.js +255 -0
- package/dist/domain/loan-contract.test.js.map +1 -0
- package/dist/domain/requests.d.ts +181 -0
- package/dist/domain/requests.js +202 -0
- package/dist/domain/requests.js.map +1 -0
- package/dist/domain/requests.test.d.ts +1 -0
- package/dist/domain/requests.test.js +470 -0
- package/dist/domain/requests.test.js.map +1 -0
- package/dist/domain/settlement.d.ts +97 -0
- package/dist/domain/settlement.js +117 -0
- package/dist/domain/settlement.js.map +1 -0
- package/dist/domain/settlement.test.d.ts +1 -0
- package/dist/domain/settlement.test.js +152 -0
- package/dist/domain/settlement.test.js.map +1 -0
- package/dist/domain/wallet-errors.d.ts +37 -0
- package/dist/domain/wallet-errors.js +56 -0
- package/dist/domain/wallet-errors.js.map +1 -0
- package/dist/domain/wallet-errors.test.d.ts +1 -0
- package/dist/domain/wallet-errors.test.js +71 -0
- package/dist/domain/wallet-errors.test.js.map +1 -0
- package/dist/facade/chain-configs.js +7 -1
- package/dist/facade/chain-configs.js.map +1 -1
- package/dist/facade/facade.test.js +82 -5
- package/dist/facade/facade.test.js.map +1 -1
- package/dist/facade/user-portfolio.d.ts +18 -0
- package/dist/facade/user-portfolio.js +23 -0
- package/dist/facade/user-portfolio.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/services/DataService/data-service.js +3 -10
- package/dist/services/DataService/data-service.js.map +1 -1
- package/dist/services/DataService/directus-client.d.ts +26 -0
- package/dist/services/DataService/directus-client.js +38 -0
- package/dist/services/DataService/directus-client.js.map +1 -0
- package/dist/services/UserLending/user-lending.js +11 -7
- package/dist/services/UserLending/user-lending.js.map +1 -1
- package/package.json +1 -1
- package/src/domain/au-minimum.test.ts +371 -0
- package/src/domain/au-minimum.ts +192 -0
- package/src/domain/index.ts +67 -3
- package/src/domain/loan-contract.test.ts +343 -0
- package/src/domain/loan-contract.ts +275 -0
- package/src/domain/requests.test.ts +653 -0
- package/src/domain/requests.ts +414 -0
- package/src/domain/settlement.test.ts +198 -0
- package/src/domain/settlement.ts +161 -0
- package/src/domain/wallet-errors.test.ts +100 -0
- package/src/domain/wallet-errors.ts +56 -0
- package/src/facade/chain-configs.ts +7 -1
- package/src/facade/facade.test.ts +124 -0
- package/src/facade/user-portfolio.ts +24 -0
- package/src/index.ts +2 -0
- package/src/services/DataService/data-service.ts +7 -24
- package/src/services/DataService/directus-client.ts +54 -0
- package/src/services/UserLending/user-lending.ts +17 -21
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cycles and the clearing window — the protocol's weekly clock, as numbers.
|
|
3
|
+
*
|
|
4
|
+
* Lifted verbatim from kasu-ui's `features/portfolio/lib/settlement-window.ts`
|
|
5
|
+
* and `features/lending/lib/cycle-dates.ts`. The two formatters that live
|
|
6
|
+
* beside `deriveCycleDates` there (`formatCycleDate`, `formatCycleCloseUtc`)
|
|
7
|
+
* print words and stay in the applications; everything here is unix seconds in
|
|
8
|
+
* and unix seconds out.
|
|
9
|
+
*
|
|
10
|
+
* The clearing window is the fixed 48 hours immediately preceding an epoch
|
|
11
|
+
* end. Inside it, pending requests are being processed and cannot be modified,
|
|
12
|
+
* and the countdown runs to the epoch end. Outside it, the countdown runs to
|
|
13
|
+
* the next clearing-window start.
|
|
14
|
+
*
|
|
15
|
+
* The epoch end comes straight from the chain (`nextEpochStartTimestamp`, i.e.
|
|
16
|
+
* the SDK's `getNextEpochDate`) — the same value the protocol's own
|
|
17
|
+
* `getNextClearingPeriodDate` derives from — so the window always lines up
|
|
18
|
+
* with the real weekly schedule (Tue 06:00 → Thu 06:00 UTC on Base) instead of
|
|
19
|
+
* a projected subgraph timestamp that can drift off the grid.
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* Clearing-window length — a fixed 48h protocol constant. Exported so every
|
|
23
|
+
* consumer derives the window from the same number this module runs on.
|
|
24
|
+
*/
|
|
25
|
+
export const CLEARING_WINDOW_SECONDS = 48 * 60 * 60;
|
|
26
|
+
/**
|
|
27
|
+
* Weekly cadence — the epoch schedule is fixed weekly (Tue → Thu UTC on Base).
|
|
28
|
+
* Used only to roll a cycle forward when a request lands inside a window that
|
|
29
|
+
* has already closed.
|
|
30
|
+
*/
|
|
31
|
+
const WEEK_SECONDS = 7 * 24 * 60 * 60;
|
|
32
|
+
/**
|
|
33
|
+
* Which phase of the weekly cycle `nowSeconds` falls in, and how long is left
|
|
34
|
+
* of it.
|
|
35
|
+
*
|
|
36
|
+
* `'unknown'` when no epoch boundary has been loaded yet, or when the one on
|
|
37
|
+
* hand is stale (it has already elapsed — the on-chain value refetches to the
|
|
38
|
+
* next boundary shortly after rollover). A caller must render its "no cycle
|
|
39
|
+
* loaded" state there, never a zeroed countdown.
|
|
40
|
+
*/
|
|
41
|
+
export function computeSettlementWindow({ nowSeconds, nextEpochStart, clearingWindowSeconds = CLEARING_WINDOW_SECONDS, }) {
|
|
42
|
+
// No epoch boundary loaded yet, or a stale one that already elapsed.
|
|
43
|
+
if (nextEpochStart <= 0 || nextEpochStart <= nowSeconds) {
|
|
44
|
+
return { phase: 'unknown' };
|
|
45
|
+
}
|
|
46
|
+
const clearingStart = nextEpochStart - clearingWindowSeconds;
|
|
47
|
+
if (nowSeconds < clearingStart) {
|
|
48
|
+
return {
|
|
49
|
+
phase: 'awaiting',
|
|
50
|
+
secondsUntilClearing: clearingStart - nowSeconds,
|
|
51
|
+
nextClearingStart: clearingStart,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
// nowSeconds is in [clearingStart, nextEpochStart) — inside the window.
|
|
55
|
+
return {
|
|
56
|
+
phase: 'clearing',
|
|
57
|
+
secondsUntilEpochEnd: nextEpochStart - nowSeconds,
|
|
58
|
+
epochEnd: nextEpochStart,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* The next cycle boundary strictly after `nowSeconds`, in unix seconds — the
|
|
63
|
+
* cycle close (`nextEpochStart − 48h`) while the window is still open, the
|
|
64
|
+
* epoch end once we are inside it.
|
|
65
|
+
*
|
|
66
|
+
* `undefined` when there is no boundary left to wait for: no epoch boundary
|
|
67
|
+
* loaded, or a cached one that has already elapsed — the same staleness rule
|
|
68
|
+
* `computeSettlementWindow` applies before it reports `'unknown'`.
|
|
69
|
+
*
|
|
70
|
+
* Split out of the state machine because some consumers need the INSTANT
|
|
71
|
+
* rather than the phase: one to flush the cycle-dependent caches when the
|
|
72
|
+
* clock crosses it, one to move a pre-commit screen's snapshot clock at the
|
|
73
|
+
* same moment.
|
|
74
|
+
*/
|
|
75
|
+
export function nextCycleBoundary(nextEpochStart, nowSeconds, clearingWindowSeconds = CLEARING_WINDOW_SECONDS) {
|
|
76
|
+
if (!nextEpochStart || nextEpochStart <= 0)
|
|
77
|
+
return undefined;
|
|
78
|
+
const clearingStart = nextEpochStart - clearingWindowSeconds;
|
|
79
|
+
if (nowSeconds < clearingStart)
|
|
80
|
+
return clearingStart;
|
|
81
|
+
if (nowSeconds < nextEpochStart)
|
|
82
|
+
return nextEpochStart;
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* The cycle-close and outcome dates for a request submitted `now`.
|
|
87
|
+
*
|
|
88
|
+
* - The cycle "closes" (stops accepting requests, starts processing) at the
|
|
89
|
+
* start of the 48h clearing window, i.e. 48h before the epoch end.
|
|
90
|
+
* - Processing takes up to 48h, so the outcome is confirmed by the epoch end
|
|
91
|
+
* (close + 48h).
|
|
92
|
+
*
|
|
93
|
+
* Returns `null` when the epoch boundary is not available or is stale — a
|
|
94
|
+
* caller then omits the dates entirely (omit, don't stub).
|
|
95
|
+
*
|
|
96
|
+
* The common case is a request submitted OUTSIDE the clearing window: the
|
|
97
|
+
* close is `nextEpochStart − 48h` and the outcome is `nextEpochStart`. When
|
|
98
|
+
* the request lands INSIDE the current clearing window (that close is already
|
|
99
|
+
* in the past), it queues for the NEXT weekly cycle, so the close is advanced
|
|
100
|
+
* by whole weeks until it is in the future.
|
|
101
|
+
*/
|
|
102
|
+
export function deriveCycleDates(nextEpochStart, nowSeconds) {
|
|
103
|
+
// No boundary loaded, or a stale one that already elapsed — the same
|
|
104
|
+
// staleness rule as `computeSettlementWindow`.
|
|
105
|
+
if (!nextEpochStart || nextEpochStart <= nowSeconds)
|
|
106
|
+
return null;
|
|
107
|
+
let close = nextEpochStart - CLEARING_WINDOW_SECONDS;
|
|
108
|
+
let outcome = nextEpochStart;
|
|
109
|
+
// Inside the current clearing window the close already passed; a request
|
|
110
|
+
// now is queued for the next weekly cycle.
|
|
111
|
+
while (close <= nowSeconds) {
|
|
112
|
+
close += WEEK_SECONDS;
|
|
113
|
+
outcome += WEEK_SECONDS;
|
|
114
|
+
}
|
|
115
|
+
return { close, outcome };
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=settlement.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settlement.js","sourceRoot":"","sources":["../../src/domain/settlement.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;AAEpD;;;;GAIG;AACH,MAAM,YAAY,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;AAwBtC;;;;;;;;GAQG;AACH,MAAM,UAAU,uBAAuB,CAAC,EACpC,UAAU,EACV,cAAc,EACd,qBAAqB,GAAG,uBAAuB,GAC3B;IACpB,qEAAqE;IACrE,IAAI,cAAc,IAAI,CAAC,IAAI,cAAc,IAAI,UAAU,EAAE,CAAC;QACtD,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;IAChC,CAAC;IAED,MAAM,aAAa,GAAG,cAAc,GAAG,qBAAqB,CAAC;IAE7D,IAAI,UAAU,GAAG,aAAa,EAAE,CAAC;QAC7B,OAAO;YACH,KAAK,EAAE,UAAU;YACjB,oBAAoB,EAAE,aAAa,GAAG,UAAU;YAChD,iBAAiB,EAAE,aAAa;SACnC,CAAC;IACN,CAAC;IAED,wEAAwE;IACxE,OAAO;QACH,KAAK,EAAE,UAAU;QACjB,oBAAoB,EAAE,cAAc,GAAG,UAAU;QACjD,QAAQ,EAAE,cAAc;KAC3B,CAAC;AACN,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,iBAAiB,CAC7B,cAAkC,EAClC,UAAkB,EAClB,wBAAgC,uBAAuB;IAEvD,IAAI,CAAC,cAAc,IAAI,cAAc,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IAC7D,MAAM,aAAa,GAAG,cAAc,GAAG,qBAAqB,CAAC;IAC7D,IAAI,UAAU,GAAG,aAAa;QAAE,OAAO,aAAa,CAAC;IACrD,IAAI,UAAU,GAAG,cAAc;QAAE,OAAO,cAAc,CAAC;IACvD,OAAO,SAAS,CAAC;AACrB,CAAC;AASD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,gBAAgB,CAC5B,cAAkC,EAClC,UAAkB;IAElB,qEAAqE;IACrE,+CAA+C;IAC/C,IAAI,CAAC,cAAc,IAAI,cAAc,IAAI,UAAU;QAAE,OAAO,IAAI,CAAC;IAEjE,IAAI,KAAK,GAAG,cAAc,GAAG,uBAAuB,CAAC;IACrD,IAAI,OAAO,GAAG,cAAc,CAAC;IAC7B,yEAAyE;IACzE,2CAA2C;IAC3C,OAAO,KAAK,IAAI,UAAU,EAAE,CAAC;QACzB,KAAK,IAAI,YAAY,CAAC;QACtB,OAAO,IAAI,YAAY,CAAC;IAC5B,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AAC9B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,152 @@
|
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settlement.test.js","sourceRoot":"","sources":["../../src/domain/settlement.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wallet and RPC error predicates — pure functions over `unknown`.
|
|
3
|
+
*
|
|
4
|
+
* Every consumer has to tell three things apart when a write fails: the lender
|
|
5
|
+
* changed their mind, the call would revert, and everything else. The first
|
|
6
|
+
* two must never be reported as a failure the lender should retry or contact
|
|
7
|
+
* support about, and each wallet spells them differently, so the shapes are
|
|
8
|
+
* enumerated once here.
|
|
9
|
+
*
|
|
10
|
+
* Lifted from kasu-ui's `src/lib/web3/is-user-rejected.ts` and kasu-mobile's
|
|
11
|
+
* `src/features/lending/lib/errors.ts`.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Did the lender reject the request in their wallet?
|
|
15
|
+
*
|
|
16
|
+
* Providers surface a rejection in different shapes:
|
|
17
|
+
* - MetaMask and most EIP-1193 wallets: `code: 4001`
|
|
18
|
+
* - WalletConnect and some Privy paths: `Error('User rejected the request')`
|
|
19
|
+
* - ethers v5 wraps it as `ACTION_REJECTED`
|
|
20
|
+
* - Coinbase Wallet sometimes: `code: 'ACTION_REJECTED'` as a string
|
|
21
|
+
*
|
|
22
|
+
* This is kasu-ui's implementation verbatim. kasu-mobile's copy additionally
|
|
23
|
+
* reads a nested `error.code` / `error.message`, an ethers `reason`, and the
|
|
24
|
+
* words "request rejected" / "declined"; a consumer that needs those shapes
|
|
25
|
+
* should keep its own check on top rather than assume they are covered here.
|
|
26
|
+
*/
|
|
27
|
+
export declare function isUserRejected(err: unknown): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Did the wallet or RPC signal that the on-chain call would revert?
|
|
30
|
+
*
|
|
31
|
+
* ethers v5 raises `UNPREDICTABLE_GAS_LIMIT` when gas estimation reverts —
|
|
32
|
+
* most often an underlying `transferFrom` failing on an insufficient balance
|
|
33
|
+
* or allowance. Distinct from a rejection: nothing was refused by the lender,
|
|
34
|
+
* the transaction simply cannot succeed as composed, so the caller should
|
|
35
|
+
* re-check its preconditions rather than invite a retry.
|
|
36
|
+
*/
|
|
37
|
+
export declare function isUnpredictableGas(err: unknown): boolean;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wallet and RPC error predicates — pure functions over `unknown`.
|
|
3
|
+
*
|
|
4
|
+
* Every consumer has to tell three things apart when a write fails: the lender
|
|
5
|
+
* changed their mind, the call would revert, and everything else. The first
|
|
6
|
+
* two must never be reported as a failure the lender should retry or contact
|
|
7
|
+
* support about, and each wallet spells them differently, so the shapes are
|
|
8
|
+
* enumerated once here.
|
|
9
|
+
*
|
|
10
|
+
* Lifted from kasu-ui's `src/lib/web3/is-user-rejected.ts` and kasu-mobile's
|
|
11
|
+
* `src/features/lending/lib/errors.ts`.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Did the lender reject the request in their wallet?
|
|
15
|
+
*
|
|
16
|
+
* Providers surface a rejection in different shapes:
|
|
17
|
+
* - MetaMask and most EIP-1193 wallets: `code: 4001`
|
|
18
|
+
* - WalletConnect and some Privy paths: `Error('User rejected the request')`
|
|
19
|
+
* - ethers v5 wraps it as `ACTION_REJECTED`
|
|
20
|
+
* - Coinbase Wallet sometimes: `code: 'ACTION_REJECTED'` as a string
|
|
21
|
+
*
|
|
22
|
+
* This is kasu-ui's implementation verbatim. kasu-mobile's copy additionally
|
|
23
|
+
* reads a nested `error.code` / `error.message`, an ethers `reason`, and the
|
|
24
|
+
* words "request rejected" / "declined"; a consumer that needs those shapes
|
|
25
|
+
* should keep its own check on top rather than assume they are covered here.
|
|
26
|
+
*/
|
|
27
|
+
export function isUserRejected(err) {
|
|
28
|
+
if (!err)
|
|
29
|
+
return false;
|
|
30
|
+
if (typeof err === 'object') {
|
|
31
|
+
const code = err.code;
|
|
32
|
+
if (code === 4001 || code === 'ACTION_REJECTED')
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
36
|
+
const lower = msg.toLowerCase();
|
|
37
|
+
return (lower.includes('user rejected') ||
|
|
38
|
+
lower.includes('user denied') ||
|
|
39
|
+
lower.includes('rejected the request') ||
|
|
40
|
+
lower.includes('action_rejected'));
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Did the wallet or RPC signal that the on-chain call would revert?
|
|
44
|
+
*
|
|
45
|
+
* ethers v5 raises `UNPREDICTABLE_GAS_LIMIT` when gas estimation reverts —
|
|
46
|
+
* most often an underlying `transferFrom` failing on an insufficient balance
|
|
47
|
+
* or allowance. Distinct from a rejection: nothing was refused by the lender,
|
|
48
|
+
* the transaction simply cannot succeed as composed, so the caller should
|
|
49
|
+
* re-check its preconditions rather than invite a retry.
|
|
50
|
+
*/
|
|
51
|
+
export function isUnpredictableGas(err) {
|
|
52
|
+
if (!err || typeof err !== 'object')
|
|
53
|
+
return false;
|
|
54
|
+
return err.code === 'UNPREDICTABLE_GAS_LIMIT';
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=wallet-errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wallet-errors.js","sourceRoot":"","sources":["../../src/domain/wallet-errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,cAAc,CAAC,GAAY;IACvC,IAAI,CAAC,GAAG;QAAE,OAAO,KAAK,CAAC;IACvB,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC1B,MAAM,IAAI,GAAI,GAA0B,CAAC,IAAI,CAAC;QAC9C,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,iBAAiB;YAAE,OAAO,IAAI,CAAC;IACjE,CAAC;IACD,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC7D,MAAM,KAAK,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;IAChC,OAAO,CACH,KAAK,CAAC,QAAQ,CAAC,eAAe,CAAC;QAC/B,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC;QAC7B,KAAK,CAAC,QAAQ,CAAC,sBAAsB,CAAC;QACtC,KAAK,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CACpC,CAAC;AACN,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAY;IAC3C,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAClD,OAAQ,GAA0B,CAAC,IAAI,KAAK,yBAAyB,CAAC;AAC1E,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { isUnpredictableGas, isUserRejected } from './wallet-errors';
|
|
2
|
+
/**
|
|
3
|
+
* `isUserRejected` cases ported from kasu-ui
|
|
4
|
+
* `src/lib/web3/is-user-rejected.test.ts`. `isUnpredictableGas` had no test in
|
|
5
|
+
* kasu-mobile; one is written here.
|
|
6
|
+
*/
|
|
7
|
+
describe('isUserRejected', () => {
|
|
8
|
+
it('detects EIP-1193 numeric code 4001', () => {
|
|
9
|
+
expect(isUserRejected({ code: 4001, message: 'whatever' })).toBe(true);
|
|
10
|
+
});
|
|
11
|
+
it('detects ACTION_REJECTED string code (ethers v5)', () => {
|
|
12
|
+
expect(isUserRejected({ code: 'ACTION_REJECTED', message: 'rejected' })).toBe(true);
|
|
13
|
+
});
|
|
14
|
+
it('detects "User rejected" message string', () => {
|
|
15
|
+
expect(isUserRejected(new Error('User rejected the request'))).toBe(true);
|
|
16
|
+
});
|
|
17
|
+
it('detects "User denied" message string', () => {
|
|
18
|
+
expect(isUserRejected(new Error('User denied transaction signature'))).toBe(true);
|
|
19
|
+
});
|
|
20
|
+
it('detects the ethers ACTION_REJECTED marker in a message', () => {
|
|
21
|
+
expect(isUserRejected(new Error('transaction failed: ACTION_REJECTED'))).toBe(true);
|
|
22
|
+
});
|
|
23
|
+
it('is case-insensitive', () => {
|
|
24
|
+
expect(isUserRejected(new Error('user REJECTED the request'))).toBe(true);
|
|
25
|
+
});
|
|
26
|
+
it('returns false for unrelated errors', () => {
|
|
27
|
+
expect(isUserRejected(new Error('Network error'))).toBe(false);
|
|
28
|
+
expect(isUserRejected(new Error('Insufficient funds'))).toBe(false);
|
|
29
|
+
});
|
|
30
|
+
it('returns false for null / undefined', () => {
|
|
31
|
+
expect(isUserRejected(null)).toBe(false);
|
|
32
|
+
expect(isUserRejected(undefined)).toBe(false);
|
|
33
|
+
});
|
|
34
|
+
it('handles non-Error throwables', () => {
|
|
35
|
+
expect(isUserRejected('user rejected')).toBe(true);
|
|
36
|
+
expect(isUserRejected('something else')).toBe(false);
|
|
37
|
+
});
|
|
38
|
+
it('is not fooled by a numeric code that only looks like 4001', () => {
|
|
39
|
+
expect(isUserRejected({ code: '4001' })).toBe(false);
|
|
40
|
+
expect(isUserRejected({ code: 4002 })).toBe(false);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
describe('isUnpredictableGas', () => {
|
|
44
|
+
it('detects the ethers v5 gas-estimation revert code', () => {
|
|
45
|
+
expect(isUnpredictableGas({ code: 'UNPREDICTABLE_GAS_LIMIT' })).toBe(true);
|
|
46
|
+
});
|
|
47
|
+
it('does not fire on a user rejection', () => {
|
|
48
|
+
expect(isUnpredictableGas({ code: 'ACTION_REJECTED' })).toBe(false);
|
|
49
|
+
expect(isUnpredictableGas({ code: 4001 })).toBe(false);
|
|
50
|
+
});
|
|
51
|
+
it('does not fire on the code appearing only in a message', () => {
|
|
52
|
+
// The code is the signal; a message mentioning it is not one, or a
|
|
53
|
+
// logged error string would be mistaken for a revert.
|
|
54
|
+
expect(isUnpredictableGas(new Error('UNPREDICTABLE_GAS_LIMIT'))).toBe(false);
|
|
55
|
+
expect(isUnpredictableGas('UNPREDICTABLE_GAS_LIMIT')).toBe(false);
|
|
56
|
+
});
|
|
57
|
+
it('returns false for null / undefined and for unrelated errors', () => {
|
|
58
|
+
expect(isUnpredictableGas(null)).toBe(false);
|
|
59
|
+
expect(isUnpredictableGas(undefined)).toBe(false);
|
|
60
|
+
expect(isUnpredictableGas(new Error('Network error'))).toBe(false);
|
|
61
|
+
});
|
|
62
|
+
it('reads the code off an ethers error object', () => {
|
|
63
|
+
const err = Object.assign(new Error('cannot estimate gas'), {
|
|
64
|
+
code: 'UNPREDICTABLE_GAS_LIMIT',
|
|
65
|
+
reason: 'execution reverted: ERC20: insufficient allowance',
|
|
66
|
+
});
|
|
67
|
+
expect(isUnpredictableGas(err)).toBe(true);
|
|
68
|
+
expect(isUserRejected(err)).toBe(false);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
//# sourceMappingURL=wallet-errors.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wallet-errors.test.js","sourceRoot":"","sources":["../../src/domain/wallet-errors.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -139,7 +139,13 @@ export const CHAIN_CONFIGS = {
|
|
|
139
139
|
ClearingCoordinator: '',
|
|
140
140
|
ExternalTVL: '',
|
|
141
141
|
},
|
|
142
|
-
|
|
142
|
+
// The frozen Plume history is indexed on the LEGACY Goldsky project,
|
|
143
|
+
// not the one the live chains use: the same path under the current
|
|
144
|
+
// project 404s. Verified 2026-09-05 — this URL answers
|
|
145
|
+
// `{ lendingPools { id name } }` with the three Plume pools; the
|
|
146
|
+
// current-project spelling returns HTTP 404. Note the `/gn` suffix,
|
|
147
|
+
// which the current project's URLs do not carry.
|
|
148
|
+
subgraphUrl: 'https://api.goldsky.com/api/public/project_cm9t3064xeuyn01tgctdo3c17/subgraphs/kasu-plume/prod/gn',
|
|
143
149
|
directusUrl: 'https://kasu-finance.directus.app/',
|
|
144
150
|
unusedPoolIds: [],
|
|
145
151
|
poolMetadataMapping: undefined,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chain-configs.js","sourceRoot":"","sources":["../../src/facade/chain-configs.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"chain-configs.js","sourceRoot":"","sources":["../../src/facade/chain-configs.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,MAAM,YAAY,GAAa;IAC3B,0BAA0B;IAC1B,wBAAwB;IACxB,4BAA4B;IAC5B,+BAA+B;CAClC,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,aAAa,GAAoE;IAC1F,IAAI,EAAE;QACF,OAAO,EAAE,IAAI;QACb,IAAI,EAAE,cAAc;QACpB,gBAAgB,EAAE,KAAK;QACvB,SAAS,EAAE;YACP,QAAQ,EAAE,4CAA4C;YACtD,WAAW,EAAE,4CAA4C;YACzD,aAAa,EAAE,4CAA4C;YAC3D,kBAAkB,EAAE,4CAA4C;YAChE,WAAW,EAAE,4CAA4C;YACzD,aAAa,EAAE,4CAA4C;YAC3D,eAAe,EAAE,4CAA4C;YAC7D,QAAQ,EAAE,4CAA4C;YACtD,kBAAkB,EAAE,4CAA4C;YAChE,mBAAmB,EAAE,4CAA4C;YACjE,QAAQ,EAAE,4CAA4C;YACtD,WAAW,EAAE,4CAA4C;SAC5D;QACD,WAAW,EACP,qGAAqG;QACzG,WAAW,EAAE,oCAAoC;QACjD,aAAa,EAAE,EAAE;QACjB,mBAAmB,EAAE,SAAS;QAC9B,WAAW,EAAE;YACT,OAAO,EAAE,4CAA4C;YACrD,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,UAAU;YAChB,QAAQ,EAAE,CAAC;YACX,YAAY,EAAE,KAAK;SACtB;QACD,OAAO,EAAE;YACL,iCAAiC;YACjC,0BAA0B;SAC7B;KACJ;IAED,GAAG,EAAE;QACD,OAAO,EAAE,EAAE;QACX,IAAI,EAAE,aAAa;QACnB,gBAAgB,EAAE,IAAI;QACtB,SAAS,EAAE;YACP,kCAAkC;YAClC,WAAW,EAAE,4CAA4C;YACzD,aAAa,EAAE,4CAA4C;YAC3D,kBAAkB,EAAE,4CAA4C;YAChE,WAAW,EAAE,4CAA4C;YACzD,aAAa,EAAE,4CAA4C;YAC3D,eAAe,EAAE,4CAA4C;YAC7D,QAAQ,EAAE,4CAA4C;YACtD,kBAAkB,EAAE,4CAA4C;YAChE,mBAAmB,EAAE,4CAA4C;YACjE,kCAAkC;YAClC,WAAW,EAAE,4CAA4C;SAC5D;QACD,WAAW,EACP,mGAAmG;QACvG,WAAW,EAAE,oCAAoC;QACjD,aAAa,EAAE,EAAE;QACjB,mBAAmB,EAAE;YACjB,4CAA4C,EACxC,4CAA4C;YAChD,4CAA4C,EACxC,4CAA4C;YAChD,4CAA4C,EACxC,4CAA4C;SACnD;QACD,WAAW,EAAE;YACT,OAAO,EAAE,4CAA4C;YACrD,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,2BAA2B;YACjC,QAAQ,EAAE,CAAC;YACX,YAAY,EAAE,KAAK;SACtB;QACD,OAAO,EAAE,YAAY;KACxB;IAED,UAAU,EAAE;QACR,OAAO,EAAE,EAAE;QACX,IAAI,EAAE,oBAAoB;QAC1B,gBAAgB,EAAE,IAAI;QACtB,SAAS,EAAE;YACP,kCAAkC;YAClC,WAAW,EAAE,4CAA4C;YACzD,aAAa,EAAE,4CAA4C;YAC3D,kBAAkB,EAAE,4CAA4C;YAChE,WAAW,EAAE,4CAA4C;YACzD,aAAa,EAAE,4CAA4C;YAC3D,eAAe,EAAE,4CAA4C;YAC7D,QAAQ,EAAE,4CAA4C;YACtD,kBAAkB,EAAE,4CAA4C;YAChE,mBAAmB,EAAE,4CAA4C;YACjE,kCAAkC;YAClC,WAAW,EAAE,4CAA4C;SAC5D;QACD,WAAW,EACP,wGAAwG;QAC5G,WAAW,EAAE,oCAAoC;QACjD,aAAa,EAAE,EAAE;QACjB,mBAAmB,EAAE,SAAS;QAC9B,WAAW,EAAE;YACT,OAAO,EAAE,4CAA4C;YACrD,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,UAAU;YAChB,QAAQ,EAAE,CAAC;YACX,YAAY,EAAE,KAAK;SACtB;QACD,OAAO,EAAE,YAAY;KACxB;IAED,KAAK,EAAE;QACH,OAAO,EAAE,KAAK;QACd,IAAI,EAAE,eAAe;QACrB,gBAAgB,EAAE,IAAI;QACtB,SAAS,EAAE;YACP,yDAAyD;YACzD,WAAW,EAAE,EAAE;YACf,aAAa,EAAE,EAAE;YACjB,kBAAkB,EAAE,EAAE;YACtB,WAAW,EAAE,EAAE;YACf,aAAa,EAAE,EAAE;YACjB,eAAe,EAAE,EAAE;YACnB,QAAQ,EAAE,EAAE;YACZ,kBAAkB,EAAE,EAAE;YACtB,mBAAmB,EAAE,EAAE;YACvB,WAAW,EAAE,EAAE;SAClB;QACD,qEAAqE;QACrE,mEAAmE;QACnE,uDAAuD;QACvD,iEAAiE;QACjE,oEAAoE;QACpE,iDAAiD;QACjD,WAAW,EACP,mGAAmG;QACvG,WAAW,EAAE,oCAAoC;QACjD,aAAa,EAAE,EAAE;QACjB,mBAAmB,EAAE,SAAS;QAC9B,WAAW,EAAE;YACT,OAAO,EAAE,4CAA4C;YACrD,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,WAAW;YACjB,QAAQ,EAAE,CAAC;YACX,YAAY,EAAE,KAAK;SACtB;QACD,mEAAmE;QACnE,+DAA+D;QAC/D,0DAA0D;QAC1D,iDAAiD;QACjD,OAAO,EAAE,EAAE;QACX,OAAO,EAAE,IAAI;KAChB;CACJ,CAAC"}
|
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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 { NO_DIRECTUS_URL_MESSAGE } from '../services/DataService/directus-client';
|
|
11
|
+
import { UserRequestStatus } from '../services/UserLending/subgraph-types';
|
|
6
12
|
import { CHAIN_CONFIGS } from './chain-configs';
|
|
7
13
|
import { DepositsFacade } from './deposits';
|
|
8
14
|
import { Kasu } from './kasu';
|
|
@@ -45,6 +51,15 @@ describe('CHAIN_CONFIGS', () => {
|
|
|
45
51
|
expect(config.subgraphUrl).toContain('goldsky.com');
|
|
46
52
|
}
|
|
47
53
|
});
|
|
54
|
+
it('plume points at the LEGACY goldsky project its frozen history is on', () => {
|
|
55
|
+
// Plume was indexed before the live chains moved to the current
|
|
56
|
+
// project; the same path under that project returns HTTP 404, so the
|
|
57
|
+
// retired deployment's history is only readable at this spelling —
|
|
58
|
+
// note the `/gn` suffix the current project's URLs do not carry.
|
|
59
|
+
const projectOf = (url) => { var _a; return (_a = url.split('/')[5]) !== null && _a !== void 0 ? _a : ''; };
|
|
60
|
+
expect(projectOf(CHAIN_CONFIGS.plume.subgraphUrl)).not.toBe(projectOf(CHAIN_CONFIGS.base.subgraphUrl));
|
|
61
|
+
expect(CHAIN_CONFIGS.plume.subgraphUrl.endsWith('/gn')).toBe(true);
|
|
62
|
+
});
|
|
48
63
|
it('xdc should have poolMetadataMapping', () => {
|
|
49
64
|
const mapping = CHAIN_CONFIGS.xdc.poolMetadataMapping;
|
|
50
65
|
expect(mapping).toBeDefined();
|
|
@@ -108,6 +123,29 @@ describe('Kasu.create()', () => {
|
|
|
108
123
|
});
|
|
109
124
|
expect(kasu).toBeInstanceOf(Kasu);
|
|
110
125
|
});
|
|
126
|
+
it('constructs without a directusUrl — on-chain data does not need one', () => {
|
|
127
|
+
// `createDirectus('')` throws `Invalid URL`, so an SDK configured
|
|
128
|
+
// without the (documented-optional) CMS URL used to be
|
|
129
|
+
// unconstructable rather than merely CMS-less.
|
|
130
|
+
const kasu = Kasu.create({
|
|
131
|
+
chain: 'base',
|
|
132
|
+
signerOrProvider: mockProvider,
|
|
133
|
+
configOverrides: { directusUrl: '' },
|
|
134
|
+
});
|
|
135
|
+
expect(kasu).toBeInstanceOf(Kasu);
|
|
136
|
+
expect(kasu.services.DataService).toBeDefined();
|
|
137
|
+
expect(kasu.services.UserLending).toBeDefined();
|
|
138
|
+
});
|
|
139
|
+
it('refuses a CMS-only call clearly when no directusUrl is configured', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
140
|
+
const kasu = Kasu.create({
|
|
141
|
+
chain: 'base',
|
|
142
|
+
signerOrProvider: mockProvider,
|
|
143
|
+
configOverrides: { directusUrl: '' },
|
|
144
|
+
});
|
|
145
|
+
// A sentence naming what to configure, not a null dereference thrown
|
|
146
|
+
// from inside the vendor SDK.
|
|
147
|
+
yield expect(kasu.services.DataService.getPlatformOverview()).rejects.toThrow(NO_DIRECTUS_URL_MESSAGE);
|
|
148
|
+
}));
|
|
111
149
|
it('should expose the underlying KasuSdk via .services', () => {
|
|
112
150
|
const kasu = Kasu.create({
|
|
113
151
|
chain: 'base',
|
|
@@ -167,6 +205,42 @@ describe('StrategiesFacade.calculateDepositLimits()', () => {
|
|
|
167
205
|
});
|
|
168
206
|
});
|
|
169
207
|
// ---------------------------------------------------------------------------
|
|
208
|
+
// PortfolioFacade.getRequestStates()
|
|
209
|
+
// ---------------------------------------------------------------------------
|
|
210
|
+
describe('PortfolioFacade.getRequestStates()', () => {
|
|
211
|
+
it('maps the transaction history through deriveRequestState', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
212
|
+
const requests = [
|
|
213
|
+
makeUserRequest({ id: 'req-1' }),
|
|
214
|
+
makeUserRequest({
|
|
215
|
+
id: 'req-2',
|
|
216
|
+
requestType: 'Withdrawal',
|
|
217
|
+
status: UserRequestStatus.PROCESSED,
|
|
218
|
+
canCancel: false,
|
|
219
|
+
acceptedAmount: '100',
|
|
220
|
+
}),
|
|
221
|
+
];
|
|
222
|
+
const userLending = {
|
|
223
|
+
getCurrentEpoch: () => Promise.resolve('42'),
|
|
224
|
+
getUserRequests: () => Promise.resolve(requests),
|
|
225
|
+
};
|
|
226
|
+
const facade = new PortfolioFacade({}, userLending, {});
|
|
227
|
+
const states = yield facade.getRequestStates('0xuser');
|
|
228
|
+
expect(states.map((s) => s.id)).toEqual(['req-1', 'req-2']);
|
|
229
|
+
expect(states[0].statusCode).toBe('pending');
|
|
230
|
+
expect(states[0].amount).toBe(100);
|
|
231
|
+
expect(states[1].statusCode).toBe('complete');
|
|
232
|
+
expect(states[1].amount).toBe(-100);
|
|
233
|
+
}));
|
|
234
|
+
it('returns an empty list for a wallet with no history', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
235
|
+
const userLending = {
|
|
236
|
+
getCurrentEpoch: () => Promise.resolve('42'),
|
|
237
|
+
getUserRequests: () => Promise.resolve([]),
|
|
238
|
+
};
|
|
239
|
+
const facade = new PortfolioFacade({}, userLending, {});
|
|
240
|
+
yield expect(facade.getRequestStates('0xuser')).resolves.toEqual([]);
|
|
241
|
+
}));
|
|
242
|
+
});
|
|
243
|
+
// ---------------------------------------------------------------------------
|
|
170
244
|
// Type exports — verify key facade types are importable
|
|
171
245
|
// ---------------------------------------------------------------------------
|
|
172
246
|
describe('Type re-exports', () => {
|
|
@@ -198,4 +272,7 @@ function makeTranche(raw) {
|
|
|
198
272
|
_raw: Object.assign(Object.assign({}, raw), { id: '0xtest', name: 'Test Tranche', apy: '0.08', minApy: '0.06', maxApy: '0.10', fixedTermConfig: [] }),
|
|
199
273
|
};
|
|
200
274
|
}
|
|
275
|
+
function makeUserRequest(overrides = {}) {
|
|
276
|
+
return Object.assign({ id: 'req-1', userId: '0xuser', lendingPool: { id: '0xpool', name: 'Pool', tranches: [{ orderId: '0' }] }, requestType: 'Deposit', trancheId: '0xtranche', trancheName: 'Senior', requestedAmount: '100', acceptedAmount: '0', rejectedAmount: '0', timestamp: 1700000000, status: UserRequestStatus.REQUESTED, canCancel: true, events: [], nftId: '', apy: '0', fixedTermConfig: undefined }, overrides);
|
|
277
|
+
}
|
|
201
278
|
//# sourceMappingURL=facade.test.js.map
|