@sly-rentals/core 5.5.2 → 6.1.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/dist/api.json +3556 -3373
- package/dist/cjs/doctor/contract.js +106 -66
- package/dist/cjs/doctor/contract.js.map +1 -1
- package/dist/cjs/doctor/contract.test.js +73 -2
- package/dist/cjs/doctor/contract.test.js.map +1 -1
- package/dist/cjs/generated/codama/instructions/closeRental.js +12 -0
- package/dist/cjs/generated/codama/instructions/closeRental.js.map +1 -1
- package/dist/cjs/idl/srsly.json +53 -2
- package/dist/cjs/instructions/closeContract.js +27 -41
- package/dist/cjs/instructions/closeContract.js.map +1 -1
- package/dist/cjs/instructions/closeContract.test.js +88 -0
- package/dist/cjs/instructions/closeContract.test.js.map +1 -1
- package/dist/cjs/instructions/closeContractThread.js +4 -4
- package/dist/cjs/instructions/closeContractThread.js.map +1 -1
- package/dist/cjs/instructions/closeRental.js +12 -1
- package/dist/cjs/instructions/closeRental.js.map +1 -1
- package/dist/cjs/instructions/deleteContractThread.js +4 -4
- package/dist/cjs/instructions/deleteContractThread.js.map +1 -1
- package/dist/cjs/legacy/closeContract.test.js +107 -0
- package/dist/cjs/legacy/closeContract.test.js.map +1 -0
- package/dist/cjs/package.json +1 -1
- package/dist/cjs/utils/fibers.js +12 -16
- package/dist/cjs/utils/fibers.js.map +1 -1
- package/dist/cjs/utils/fibers.test.js +21 -28
- package/dist/cjs/utils/fibers.test.js.map +1 -1
- package/dist/cjs/utils/rpc.js +43 -0
- package/dist/cjs/utils/rpc.js.map +1 -1
- package/dist/cjs/utils/rpc.test.js +60 -0
- package/dist/cjs/utils/rpc.test.js.map +1 -0
- package/dist/cjs/version.js +1 -1
- package/dist/esm/doctor/contract.js +107 -67
- package/dist/esm/doctor/contract.js.map +1 -1
- package/dist/esm/doctor/contract.test.js +73 -2
- package/dist/esm/doctor/contract.test.js.map +1 -1
- package/dist/esm/generated/codama/instructions/closeRental.js +12 -0
- package/dist/esm/generated/codama/instructions/closeRental.js.map +1 -1
- package/dist/esm/idl/srsly.json +53 -2
- package/dist/esm/instructions/closeContract.js +29 -43
- package/dist/esm/instructions/closeContract.js.map +1 -1
- package/dist/esm/instructions/closeContract.test.js +88 -0
- package/dist/esm/instructions/closeContract.test.js.map +1 -1
- package/dist/esm/instructions/closeContractThread.js +6 -6
- package/dist/esm/instructions/closeContractThread.js.map +1 -1
- package/dist/esm/instructions/closeRental.js +13 -2
- package/dist/esm/instructions/closeRental.js.map +1 -1
- package/dist/esm/instructions/deleteContractThread.js +6 -6
- package/dist/esm/instructions/deleteContractThread.js.map +1 -1
- package/dist/esm/legacy/closeContract.test.js +105 -0
- package/dist/esm/legacy/closeContract.test.js.map +1 -0
- package/dist/esm/package.json +1 -1
- package/dist/esm/utils/fibers.js +11 -15
- package/dist/esm/utils/fibers.js.map +1 -1
- package/dist/esm/utils/fibers.test.js +22 -29
- package/dist/esm/utils/fibers.test.js.map +1 -1
- package/dist/esm/utils/rpc.js +41 -0
- package/dist/esm/utils/rpc.js.map +1 -1
- package/dist/esm/utils/rpc.test.js +58 -0
- package/dist/esm/utils/rpc.test.js.map +1 -0
- package/dist/esm/version.js +1 -1
- package/dist/idl/srsly.json +53 -2
- package/dist/types/doctor/contract.d.ts +23 -1
- package/dist/types/doctor/contract.d.ts.map +1 -1
- package/dist/types/generated/codama/instructions/closeRental.d.ts +46 -1
- package/dist/types/generated/codama/instructions/closeRental.d.ts.map +1 -1
- package/dist/types/instructions/closeContract.d.ts +6 -3
- package/dist/types/instructions/closeContract.d.ts.map +1 -1
- package/dist/types/instructions/closeContractThread.d.ts.map +1 -1
- package/dist/types/instructions/closeRental.d.ts.map +1 -1
- package/dist/types/instructions/deleteContractThread.d.ts.map +1 -1
- package/dist/types/legacy/closeContract.test.d.ts +2 -0
- package/dist/types/legacy/closeContract.test.d.ts.map +1 -0
- package/dist/types/utils/fibers.d.ts +10 -9
- package/dist/types/utils/fibers.d.ts.map +1 -1
- package/dist/types/utils/rpc.d.ts +18 -0
- package/dist/types/utils/rpc.d.ts.map +1 -1
- package/dist/types/utils/rpc.test.d.ts +2 -0
- package/dist/types/utils/rpc.test.d.ts.map +1 -0
- package/dist/types/version.d.ts +1 -1
- package/package.json +1 -1
|
@@ -2,50 +2,43 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const vitest_1 = require("vitest");
|
|
4
4
|
const kit_1 = require("@solana/kit");
|
|
5
|
-
vitest_1.vi.mock('./rpc', () => ({ createRpc: vitest_1.vi.fn() }));
|
|
6
5
|
vitest_1.vi.mock('../pda/thread', () => ({ deriveFiber: vitest_1.vi.fn() }));
|
|
7
|
-
const rpc_1 = require("./rpc");
|
|
8
6
|
const thread_1 = require("../pda/thread");
|
|
9
7
|
const fibers_1 = require("./fibers");
|
|
10
8
|
const THREAD = 'Sysvar1nstructions1111111111111111111111111';
|
|
11
9
|
const FIBER_0 = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v';
|
|
12
10
|
const FIBER_1 = 'So11111111111111111111111111111111111111112';
|
|
13
|
-
/** `getMultipleAccounts` returns `null` in the slot of an account that does not exist. */
|
|
14
|
-
function mockAccounts(value) {
|
|
15
|
-
const send = vitest_1.vi.fn().mockResolvedValue({ value });
|
|
16
|
-
vitest_1.vi.mocked(rpc_1.createRpc).mockReturnValue({
|
|
17
|
-
getMultipleAccounts: vitest_1.vi.fn().mockReturnValue({ send }),
|
|
18
|
-
});
|
|
19
|
-
return send;
|
|
20
|
-
}
|
|
21
11
|
(0, vitest_1.beforeEach)(() => {
|
|
22
12
|
vitest_1.vi.clearAllMocks();
|
|
23
13
|
vitest_1.vi.mocked(thread_1.deriveFiber).mockImplementation(async (_thread, index) => index === 0 ? FIBER_0 : FIBER_1);
|
|
24
14
|
});
|
|
25
|
-
(0, vitest_1.describe)('
|
|
26
|
-
(0, vitest_1.it)('
|
|
15
|
+
(0, vitest_1.describe)('trackedFiberAccounts', () => {
|
|
16
|
+
(0, vitest_1.it)('carries a tracked fiber whose account is gone', async () => {
|
|
27
17
|
// The state the 2026-08-26 rent sweep left behind: the thread still tracks
|
|
28
|
-
// both indices, but fiber 1's account was closed.
|
|
29
|
-
//
|
|
30
|
-
//
|
|
31
|
-
|
|
32
|
-
const accounts = await (0, fibers_1.
|
|
33
|
-
(0, vitest_1.expect)(accounts).toEqual([
|
|
18
|
+
// both indices, but fiber 1's account was closed. The id has to be
|
|
19
|
+
// accounted for or `thread_close` fails with `MissingFiberAccounts`, and
|
|
20
|
+
// passing the account is the only way to account for it — dropping the id
|
|
21
|
+
// is the thread program's call, and only it can edit `fiber_ids`.
|
|
22
|
+
const accounts = await (0, fibers_1.trackedFiberAccounts)(THREAD, [0, 1]);
|
|
23
|
+
(0, vitest_1.expect)(accounts).toEqual([
|
|
24
|
+
{ address: FIBER_0, role: kit_1.AccountRole.WRITABLE },
|
|
25
|
+
{ address: FIBER_1, role: kit_1.AccountRole.WRITABLE },
|
|
26
|
+
]);
|
|
34
27
|
});
|
|
35
|
-
(0, vitest_1.it)('
|
|
36
|
-
|
|
37
|
-
const accounts = await (0, fibers_1.existingFiberAccounts)(THREAD, [0, 1], 'https://rpc.example');
|
|
28
|
+
(0, vitest_1.it)('carries every fiber when all of them exist', async () => {
|
|
29
|
+
const accounts = await (0, fibers_1.trackedFiberAccounts)(THREAD, [0, 1]);
|
|
38
30
|
(0, vitest_1.expect)(accounts.map(a => a.address)).toEqual([FIBER_0, FIBER_1]);
|
|
39
31
|
});
|
|
40
|
-
(0, vitest_1.it)('returns nothing when the thread tracks nothing
|
|
41
|
-
const
|
|
42
|
-
const accounts = await (0, fibers_1.existingFiberAccounts)(THREAD, [], 'https://rpc.example');
|
|
32
|
+
(0, vitest_1.it)('returns nothing when the thread tracks nothing', async () => {
|
|
33
|
+
const accounts = await (0, fibers_1.trackedFiberAccounts)(THREAD, []);
|
|
43
34
|
(0, vitest_1.expect)(accounts).toEqual([]);
|
|
44
|
-
(0, vitest_1.expect)(
|
|
35
|
+
(0, vitest_1.expect)(thread_1.deriveFiber).not.toHaveBeenCalled();
|
|
45
36
|
});
|
|
46
|
-
(0, vitest_1.it)('
|
|
47
|
-
|
|
48
|
-
|
|
37
|
+
(0, vitest_1.it)('reads no account state, so it needs no RPC', async () => {
|
|
38
|
+
// Existence is not consulted at all — the addresses are pure computation
|
|
39
|
+
// from the thread and the ids.
|
|
40
|
+
await (0, fibers_1.trackedFiberAccounts)(THREAD, [0, 1]);
|
|
41
|
+
(0, vitest_1.expect)(thread_1.deriveFiber).toHaveBeenCalledTimes(2);
|
|
49
42
|
});
|
|
50
43
|
});
|
|
51
44
|
//# sourceMappingURL=fibers.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fibers.test.js","sourceRoot":"","sources":["../../../src/utils/fibers.test.ts"],"names":[],"mappings":";;AAAA,mCAA8D;AAC9D,qCAAwD;AAExD,WAAE,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"fibers.test.js","sourceRoot":"","sources":["../../../src/utils/fibers.test.ts"],"names":[],"mappings":";;AAAA,mCAA8D;AAC9D,qCAAwD;AAExD,WAAE,CAAC,IAAI,CAAC,eAAe,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,WAAW,EAAE,WAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;AAE3D,0CAA4C;AAC5C,qCAAgD;AAEhD,MAAM,MAAM,GAAG,6CAAwD,CAAC;AACxE,MAAM,OAAO,GAAG,8CAAyD,CAAC;AAC1E,MAAM,OAAO,GAAG,6CAAwD,CAAC;AAEzE,IAAA,mBAAU,EAAC,GAAG,EAAE;IACd,WAAE,CAAC,aAAa,EAAE,CAAC;IACnB,WAAE,CAAC,MAAM,CAAC,oBAAW,CAAC,CAAC,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,CACjE,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAChC,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,IAAA,iBAAQ,EAAC,sBAAsB,EAAE,GAAG,EAAE;IACpC,IAAA,WAAE,EAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;QAC7D,2EAA2E;QAC3E,mEAAmE;QACnE,yEAAyE;QACzE,0EAA0E;QAC1E,kEAAkE;QAClE,MAAM,QAAQ,GAAG,MAAM,IAAA,6BAAoB,EAAC,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAE5D,IAAA,eAAM,EAAC,QAAQ,CAAC,CAAC,OAAO,CAAC;YACvB,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,iBAAW,CAAC,QAAQ,EAAE;YAChD,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,iBAAW,CAAC,QAAQ,EAAE;SACjD,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;QAC1D,MAAM,QAAQ,GAAG,MAAM,IAAA,6BAAoB,EAAC,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAE5D,IAAA,eAAM,EAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;IACnE,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,gDAAgD,EAAE,KAAK,IAAI,EAAE;QAC9D,MAAM,QAAQ,GAAG,MAAM,IAAA,6BAAoB,EAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAExD,IAAA,eAAM,EAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC7B,IAAA,eAAM,EAAC,oBAAW,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;QAC1D,yEAAyE;QACzE,+BAA+B;QAC/B,MAAM,IAAA,6BAAoB,EAAC,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAE3C,IAAA,eAAM,EAAC,oBAAW,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/dist/cjs/utils/rpc.js
CHANGED
|
@@ -6,9 +6,11 @@
|
|
|
6
6
|
* to add environment-specific configurations or debugging in the future.
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.MAX_MULTIPLE_ACCOUNTS = void 0;
|
|
9
10
|
exports.setRpcDebug = setRpcDebug;
|
|
10
11
|
exports.isRpcDebugEnabled = isRpcDebugEnabled;
|
|
11
12
|
exports.createRpc = createRpc;
|
|
13
|
+
exports.sendWithRetry = sendWithRetry;
|
|
12
14
|
const kit_1 = require("@solana/kit");
|
|
13
15
|
// Debug flag - can be set via setSdkConfig or environment
|
|
14
16
|
let debugMode = false;
|
|
@@ -54,4 +56,45 @@ function createRpc(rpcUrl) {
|
|
|
54
56
|
}
|
|
55
57
|
return (0, kit_1.createSolanaRpc)(rpcUrl);
|
|
56
58
|
}
|
|
59
|
+
/** Largest account list `getMultipleAccounts` accepts in one request. */
|
|
60
|
+
exports.MAX_MULTIPLE_ACCOUNTS = 100;
|
|
61
|
+
/** Providers signal "slow down" as 429, and the wording varies by host. */
|
|
62
|
+
function isRateLimited(error) {
|
|
63
|
+
const e = error;
|
|
64
|
+
if (e?.statusCode === 429 || e?.status === 429)
|
|
65
|
+
return true;
|
|
66
|
+
const message = String(e?.message ?? error);
|
|
67
|
+
return message.includes('429') || /too many requests/i.test(message);
|
|
68
|
+
}
|
|
69
|
+
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
|
70
|
+
/**
|
|
71
|
+
* Run an RPC call, backing off and retrying when the provider rate-limits it.
|
|
72
|
+
*
|
|
73
|
+
* A 429 is not a result — it means the question was never asked, so a caller
|
|
74
|
+
* that treats it as one reports on state it never read. Backoff is exponential
|
|
75
|
+
* with jitter so workers that trip the limit together do not retry together.
|
|
76
|
+
*
|
|
77
|
+
* @param send - Performs the call. Invoked again on each retry.
|
|
78
|
+
* @param options.retries - Extra attempts after the first. Defaults to 5.
|
|
79
|
+
* @param options.baseDelayMs - Delay before the first retry. Defaults to 250.
|
|
80
|
+
* @throws The last error, once retries are exhausted or it is not a 429.
|
|
81
|
+
*/
|
|
82
|
+
async function sendWithRetry(send, options = {}) {
|
|
83
|
+
const retries = options.retries ?? 5;
|
|
84
|
+
const baseDelayMs = options.baseDelayMs ?? 250;
|
|
85
|
+
let lastError;
|
|
86
|
+
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
87
|
+
try {
|
|
88
|
+
return await send();
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
lastError = error;
|
|
92
|
+
if (!isRateLimited(error) || attempt === retries)
|
|
93
|
+
throw error;
|
|
94
|
+
const backoff = baseDelayMs * 2 ** attempt;
|
|
95
|
+
await delay(backoff + Math.floor(Math.random() * backoff));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
throw lastError;
|
|
99
|
+
}
|
|
57
100
|
//# sourceMappingURL=rpc.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rpc.js","sourceRoot":"","sources":["../../../src/utils/rpc.ts"],"names":[],"mappings":";AAAA;;;;;GAKG
|
|
1
|
+
{"version":3,"file":"rpc.js","sourceRoot":"","sources":["../../../src/utils/rpc.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAWH,kCAEC;AAKD,8CAEC;AAqBD,8BASC;AA2BD,sCAmBC;AA9FD,qCAA2E;AAE3E,0DAA0D;AAC1D,IAAI,SAAS,GAAG,KAAK,CAAC;AAEtB;;;GAGG;AACH,SAAgB,WAAW,CAAC,OAAgB;IAC1C,SAAS,GAAG,OAAO,CAAC;AACtB,CAAC;AAED;;GAEG;AACH,SAAgB,iBAAiB;IAC/B,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,SAAgB,SAAS,CAAC,MAAc;IACtC,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,wCAAwC,EAAE;YACpD,GAAG,EAAE,MAAM;YACX,WAAW,EAAE,OAAO,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM;YAC/D,SAAS,EAAE,OAAO,SAAS,KAAK,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK;SAC1E,CAAC,CAAC;IACL,CAAC;IACD,OAAO,IAAA,qBAAe,EAAC,MAAM,CAAC,CAAC;AACjC,CAAC;AAED,yEAAyE;AAC5D,QAAA,qBAAqB,GAAG,GAAG,CAAC;AAEzC,2EAA2E;AAC3E,SAAS,aAAa,CAAC,KAAc;IACnC,MAAM,CAAC,GAAG,KAAoE,CAAC;IAC/E,IAAI,CAAC,EAAE,UAAU,KAAK,GAAG,IAAI,CAAC,EAAE,MAAM,KAAK,GAAG;QAAE,OAAO,IAAI,CAAC;IAC5D,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC,EAAE,OAAO,IAAI,KAAK,CAAC,CAAC;IAC5C,OAAO,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,oBAAoB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AACvE,CAAC;AAED,MAAM,KAAK,GAAG,CAAC,EAAU,EAAE,EAAE,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAE9E;;;;;;;;;;;GAWG;AACI,KAAK,UAAU,aAAa,CACjC,IAAsB,EACtB,UAAsD,EAAE;IAExD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,CAAC,CAAC;IACrC,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,GAAG,CAAC;IAE/C,IAAI,SAAkB,CAAC;IACvB,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC;QACpD,IAAI,CAAC;YACH,OAAO,MAAM,IAAI,EAAE,CAAC;QACtB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,SAAS,GAAG,KAAK,CAAC;YAClB,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,OAAO,KAAK,OAAO;gBAAE,MAAM,KAAK,CAAC;YAC9D,MAAM,OAAO,GAAG,WAAW,GAAG,CAAC,IAAI,OAAO,CAAC;YAC3C,MAAM,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC;IACD,MAAM,SAAS,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
/** A 429 means the question never reached the provider, not that it answered. */
|
|
4
|
+
const vitest_1 = require("vitest");
|
|
5
|
+
const rpc_1 = require("./rpc");
|
|
6
|
+
(0, vitest_1.beforeEach)(() => {
|
|
7
|
+
vitest_1.vi.useFakeTimers();
|
|
8
|
+
});
|
|
9
|
+
(0, vitest_1.afterEach)(() => {
|
|
10
|
+
vitest_1.vi.useRealTimers();
|
|
11
|
+
});
|
|
12
|
+
/** Drives the fake clock until `promise` settles, so backoff sleeps resolve. */
|
|
13
|
+
async function runToCompletion(promise) {
|
|
14
|
+
const settled = promise.then(value => ({ ok: true, value }), error => ({ ok: false, error }));
|
|
15
|
+
await vitest_1.vi.runAllTimersAsync();
|
|
16
|
+
const outcome = await settled;
|
|
17
|
+
if (!outcome.ok)
|
|
18
|
+
throw outcome.error;
|
|
19
|
+
return outcome.value;
|
|
20
|
+
}
|
|
21
|
+
(0, vitest_1.describe)('sendWithRetry', () => {
|
|
22
|
+
(0, vitest_1.it)('returns the first result when nothing is rate limited', async () => {
|
|
23
|
+
const send = vitest_1.vi.fn().mockResolvedValue('ok');
|
|
24
|
+
await (0, vitest_1.expect)(runToCompletion((0, rpc_1.sendWithRetry)(send))).resolves.toBe('ok');
|
|
25
|
+
(0, vitest_1.expect)(send).toHaveBeenCalledTimes(1);
|
|
26
|
+
});
|
|
27
|
+
(0, vitest_1.it)('retries a 429 and returns the eventual success', async () => {
|
|
28
|
+
const send = vitest_1.vi
|
|
29
|
+
.fn()
|
|
30
|
+
.mockRejectedValueOnce(new Error('HTTP error (429): Too Many Requests'))
|
|
31
|
+
.mockRejectedValueOnce(new Error('HTTP error (429): Too Many Requests'))
|
|
32
|
+
.mockResolvedValue('ok');
|
|
33
|
+
await (0, vitest_1.expect)(runToCompletion((0, rpc_1.sendWithRetry)(send))).resolves.toBe('ok');
|
|
34
|
+
(0, vitest_1.expect)(send).toHaveBeenCalledTimes(3);
|
|
35
|
+
});
|
|
36
|
+
(0, vitest_1.it)('recognises a rate limit from a status code alone', async () => {
|
|
37
|
+
const err = Object.assign(new Error('rejected'), { statusCode: 429 });
|
|
38
|
+
const send = vitest_1.vi.fn().mockRejectedValueOnce(err).mockResolvedValue('ok');
|
|
39
|
+
await (0, vitest_1.expect)(runToCompletion((0, rpc_1.sendWithRetry)(send))).resolves.toBe('ok');
|
|
40
|
+
(0, vitest_1.expect)(send).toHaveBeenCalledTimes(2);
|
|
41
|
+
});
|
|
42
|
+
(0, vitest_1.it)('does not retry an error that is not a rate limit', async () => {
|
|
43
|
+
// Retrying a decode failure or a bad request just multiplies the damage.
|
|
44
|
+
const send = vitest_1.vi.fn().mockRejectedValue(new Error('Invalid param: bad address'));
|
|
45
|
+
await (0, vitest_1.expect)(runToCompletion((0, rpc_1.sendWithRetry)(send))).rejects.toThrow('Invalid param');
|
|
46
|
+
(0, vitest_1.expect)(send).toHaveBeenCalledTimes(1);
|
|
47
|
+
});
|
|
48
|
+
(0, vitest_1.it)('gives up after the retry budget and surfaces the rate limit', async () => {
|
|
49
|
+
// The caller has to be able to tell "still limited" from "answered", so the
|
|
50
|
+
// final failure propagates rather than resolving to something empty.
|
|
51
|
+
const send = vitest_1.vi.fn().mockRejectedValue(new Error('HTTP error (429): Too Many Requests'));
|
|
52
|
+
await (0, vitest_1.expect)(runToCompletion((0, rpc_1.sendWithRetry)(send, { retries: 2 }))).rejects.toThrow('429');
|
|
53
|
+
(0, vitest_1.expect)(send).toHaveBeenCalledTimes(3);
|
|
54
|
+
});
|
|
55
|
+
(0, vitest_1.it)('batches at the getMultipleAccounts ceiling', () => {
|
|
56
|
+
// Asking for more than this in one call is rejected outright by the RPC.
|
|
57
|
+
(0, vitest_1.expect)(rpc_1.MAX_MULTIPLE_ACCOUNTS).toBe(100);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
//# sourceMappingURL=rpc.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rpc.test.js","sourceRoot":"","sources":["../../../src/utils/rpc.test.ts"],"names":[],"mappings":"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"}
|
package/dist/cjs/version.js
CHANGED
|
@@ -3,5 +3,5 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.VERSION = void 0;
|
|
4
4
|
// Auto-generated from package.json - DO NOT EDIT
|
|
5
5
|
// Run "pnpm run generate:version" to update
|
|
6
|
-
exports.VERSION = '
|
|
6
|
+
exports.VERSION = '6.1.0';
|
|
7
7
|
//# sourceMappingURL=version.js.map
|
|
@@ -9,7 +9,7 @@ import { getAddressDecoder, getBase64Encoder } from '@solana/kit';
|
|
|
9
9
|
import { getThreadDecoder } from '../generated/codama/types/thread';
|
|
10
10
|
import { getConfigStateDecoder, getContractStateDecoder, getRentalStateDecoder, } from '../generated/codama/accounts';
|
|
11
11
|
import { getRpcUrl } from '../utils/config';
|
|
12
|
-
import { createRpc } from '../utils/rpc';
|
|
12
|
+
import { createRpc, sendWithRetry, MAX_MULTIPLE_ACCOUNTS } from '../utils/rpc';
|
|
13
13
|
import { deriveFiber } from '../pda/thread';
|
|
14
14
|
import { deriveConfig } from '../pda/srsly';
|
|
15
15
|
import { deriveAssociatedTokenAccount } from '../pda/token';
|
|
@@ -81,15 +81,21 @@ export async function diagnoseContract(contractAddress, options = {}) {
|
|
|
81
81
|
const rpc = createRpc(options.rpcUrl || getRpcUrl());
|
|
82
82
|
const now = options.nowSeconds ?? BigInt(Math.floor(Date.now() / 1000));
|
|
83
83
|
const contractAddr = contractAddress;
|
|
84
|
-
// Config rides along with the contract
|
|
85
|
-
//
|
|
86
|
-
//
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
.
|
|
91
|
-
|
|
92
|
-
|
|
84
|
+
// Config rides along with the contract: `atlas_mint` derives the owner's
|
|
85
|
+
// payout ATA, which the second batch needs. A bulk scan has already read both
|
|
86
|
+
// in batches, so it passes them in rather than paying for them per contract.
|
|
87
|
+
let contract;
|
|
88
|
+
let config;
|
|
89
|
+
if (options.prefetched) {
|
|
90
|
+
contract = options.prefetched.contract;
|
|
91
|
+
config = options.prefetched.config;
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
const configAddr = await deriveConfig();
|
|
95
|
+
const first = await sendWithRetry(() => rpc.getMultipleAccounts([contractAddr, configAddr], { encoding: 'base64' }).send());
|
|
96
|
+
contract = decodeOrNull(first.value[0]?.data, bytes => getContractStateDecoder().decode(bytes));
|
|
97
|
+
config = decodeOrNull(first.value[1]?.data, bytes => getConfigStateDecoder().decode(bytes));
|
|
98
|
+
}
|
|
93
99
|
const findings = [];
|
|
94
100
|
const empty = {
|
|
95
101
|
contract: contractAddr,
|
|
@@ -113,81 +119,96 @@ export async function diagnoseContract(contractAddress, options = {}) {
|
|
|
113
119
|
ownerClaimable: contract.ownerClaimable,
|
|
114
120
|
feeClaimable: contract.feeClaimable,
|
|
115
121
|
};
|
|
116
|
-
|
|
117
|
-
findings.push({
|
|
118
|
-
code: 'threadNotConfigured',
|
|
119
|
-
severity: 'warning',
|
|
120
|
-
message: 'Contract has no automation thread. Nothing settles on its own.',
|
|
121
|
-
});
|
|
122
|
-
return { ...empty, owner: contract.owner, fleet: contract.fleet, healthy: true, atRisk };
|
|
123
|
-
}
|
|
124
|
-
const thread = contract.thread;
|
|
122
|
+
const thread = contract.thread === SYSTEM_PROGRAM_ID ? null : contract.thread;
|
|
125
123
|
const hasActiveRental = contract.activeRental !== SYSTEM_PROGRAM_ID;
|
|
126
|
-
// One round trip for the thread, both fiber PDAs, the active rental
|
|
127
|
-
// owner's payout ATA.
|
|
128
|
-
|
|
124
|
+
// One round trip for the thread, both fiber PDAs, the active rental and the
|
|
125
|
+
// owner's payout ATA. Built positionally because a threadless contract still
|
|
126
|
+
// has a rental worth reading — bailing on the thread is what used to report
|
|
127
|
+
// an overdue rental as healthy.
|
|
128
|
+
const fiberAddresses = thread
|
|
129
|
+
? await Promise.all(KNOWN_FIBER_INDICES.map(i => deriveFiber(thread, i)))
|
|
130
|
+
: [];
|
|
129
131
|
const ownerTokenAccount = config
|
|
130
132
|
? await deriveAssociatedTokenAccount(contract.owner, config.atlasMint)
|
|
131
133
|
: null;
|
|
132
134
|
const probe = [
|
|
133
|
-
thread,
|
|
134
|
-
...fiberAddresses,
|
|
135
|
+
...(thread ? [thread, ...fiberAddresses] : []),
|
|
135
136
|
...(hasActiveRental ? [contract.activeRental] : []),
|
|
136
137
|
...(ownerTokenAccount ? [ownerTokenAccount] : []),
|
|
137
138
|
];
|
|
138
|
-
const multi = await rpc.getMultipleAccounts(probe, { encoding: 'base64' }).send();
|
|
139
|
-
|
|
140
|
-
const
|
|
141
|
-
const
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
139
|
+
const multi = await sendWithRetry(() => rpc.getMultipleAccounts(probe, { encoding: 'base64' }).send());
|
|
140
|
+
let slot = 0;
|
|
141
|
+
const threadAcct = thread ? multi.value[slot++] : null;
|
|
142
|
+
const fiberAccts = thread ? KNOWN_FIBER_INDICES.map(() => multi.value[slot++]) : [];
|
|
143
|
+
const activeRentalAcct = hasActiveRental ? multi.value[slot++] : null;
|
|
144
|
+
const ownerTokenAcct = ownerTokenAccount ? multi.value[slot++] : null;
|
|
145
|
+
const threadLamports = threadAcct ? BigInt(threadAcct.lamports) : null;
|
|
146
|
+
const missingFibers = [];
|
|
147
|
+
if (!thread) {
|
|
148
|
+
findings.push({
|
|
149
|
+
code: 'threadNotConfigured',
|
|
150
|
+
severity: 'warning',
|
|
151
|
+
message: 'Contract has no automation thread. Nothing settles on its own.',
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
else if (!threadAcct) {
|
|
146
155
|
findings.push({
|
|
147
156
|
code: 'threadMissing',
|
|
148
157
|
severity: 'critical',
|
|
149
158
|
message: `Thread ${thread} does not exist. Recreate it with createContractThread — ` +
|
|
150
159
|
'rewriting a fiber would strand rent in an account nothing references.',
|
|
151
160
|
});
|
|
152
|
-
return { ...empty, owner: contract.owner, fleet: contract.fleet, thread, atRisk };
|
|
153
161
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
162
|
+
else {
|
|
163
|
+
const threadData = decodeOrNull(threadAcct.data, bytes => getThreadDecoder().decode(bytes.subarray(DISCRIMINATOR_SIZE)));
|
|
164
|
+
if (threadData) {
|
|
165
|
+
const tracked = new Set(Array.from(threadData.fiberIds));
|
|
166
|
+
KNOWN_FIBER_INDICES.forEach((index, i) => {
|
|
167
|
+
// Only a *tracked* index is a fault. Fiber 1 is legitimately absent
|
|
168
|
+
// until a rental is accepted, so its absence alone proves nothing.
|
|
169
|
+
if (!tracked.has(index))
|
|
170
|
+
return;
|
|
171
|
+
if (fiberAccts[i])
|
|
172
|
+
return;
|
|
173
|
+
missingFibers.push(index);
|
|
174
|
+
findings.push({
|
|
175
|
+
code: 'fiberMissing',
|
|
176
|
+
severity: 'critical',
|
|
177
|
+
message: `Thread tracks fiber ${index} but ${fiberAddresses[i]} does not exist. ` +
|
|
178
|
+
'Every execution fails to build, so the contract cannot settle. ' +
|
|
179
|
+
'Plan the repair with `antegen thread doctor --plan`, then replay it.',
|
|
180
|
+
fiberIndex: index,
|
|
181
|
+
fiber: fiberAddresses[i],
|
|
182
|
+
});
|
|
175
183
|
});
|
|
176
|
-
|
|
177
|
-
|
|
184
|
+
if (threadData.paused && hasActiveRental) {
|
|
185
|
+
findings.push({
|
|
186
|
+
code: 'threadPaused',
|
|
187
|
+
severity: 'critical',
|
|
188
|
+
message: 'A rental is active but the thread is paused, so nothing will settle.',
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
if (threadLamports !== null && threadLamports < THREAD_LAMPORTS_FLOOR) {
|
|
178
193
|
findings.push({
|
|
179
|
-
code: '
|
|
180
|
-
severity: '
|
|
181
|
-
message:
|
|
194
|
+
code: 'threadUnderfunded',
|
|
195
|
+
severity: 'warning',
|
|
196
|
+
message: `Thread holds ${threadLamports} lamports, below the ${THREAD_LAMPORTS_FLOOR} floor ` +
|
|
197
|
+
'needed to keep paying for its own executions. Top it up with updateContractThread.',
|
|
182
198
|
});
|
|
183
199
|
}
|
|
184
200
|
}
|
|
185
|
-
|
|
201
|
+
// `contract_process` is the only automated route from `to_close` to a closed
|
|
202
|
+
// contract. Latched without a live thread, nothing will ever act on it.
|
|
203
|
+
if (contract.toClose && !threadAcct) {
|
|
186
204
|
findings.push({
|
|
187
|
-
code: '
|
|
188
|
-
severity: '
|
|
189
|
-
message:
|
|
190
|
-
|
|
205
|
+
code: 'closeStranded',
|
|
206
|
+
severity: 'critical',
|
|
207
|
+
message: 'Contract is flagged to_close but has no live thread to complete the close. ' +
|
|
208
|
+
(hasActiveRental
|
|
209
|
+
? 'Nothing will close the rental when it ends, and nothing will close the contract after. '
|
|
210
|
+
: 'The slot is already empty, so the close only needs running. ') +
|
|
211
|
+
'Run closeContract to finish it.',
|
|
191
212
|
});
|
|
192
213
|
}
|
|
193
214
|
if (ownerTokenAccount && !ownerTokenAcct) {
|
|
@@ -252,14 +273,33 @@ export async function diagnoseContract(contractAddress, options = {}) {
|
|
|
252
273
|
*/
|
|
253
274
|
export async function diagnoseAllContracts(options = {}) {
|
|
254
275
|
const addresses = await fetchAllContractAddresses(options.rpcUrl);
|
|
255
|
-
const concurrency = Math.max(1, options.concurrency ??
|
|
276
|
+
const concurrency = Math.max(1, options.concurrency ?? 4);
|
|
256
277
|
const results = new Array(addresses.length);
|
|
257
278
|
let cursor = 0;
|
|
258
279
|
let done = 0;
|
|
280
|
+
// Read every contract up front, `MAX_MULTIPLE_ACCOUNTS` at a time, plus the
|
|
281
|
+
// one config account they all share. Diagnosing them individually asked for
|
|
282
|
+
// the same two accounts per contract, so a 407-contract sweep opened with 407
|
|
283
|
+
// round trips before probing anything — enough to exhaust a provider's rate
|
|
284
|
+
// limit and have most of the scan come back 429 rather than diagnosed.
|
|
285
|
+
const rpc = createRpc(options.rpcUrl || getRpcUrl());
|
|
286
|
+
const configAddr = await deriveConfig();
|
|
287
|
+
const config = decodeOrNull((await sendWithRetry(() => rpc.getMultipleAccounts([configAddr], { encoding: 'base64' }).send())).value[0]?.data, bytes => getConfigStateDecoder().decode(bytes));
|
|
288
|
+
const contracts = new Map();
|
|
289
|
+
for (let i = 0; i < addresses.length; i += MAX_MULTIPLE_ACCOUNTS) {
|
|
290
|
+
const chunk = addresses.slice(i, i + MAX_MULTIPLE_ACCOUNTS);
|
|
291
|
+
const batch = await sendWithRetry(() => rpc.getMultipleAccounts(chunk, { encoding: 'base64' }).send());
|
|
292
|
+
chunk.forEach((addr, j) => {
|
|
293
|
+
contracts.set(addr, decodeOrNull(batch.value[j]?.data, bytes => getContractStateDecoder().decode(bytes)));
|
|
294
|
+
});
|
|
295
|
+
}
|
|
259
296
|
async function worker() {
|
|
260
297
|
for (let i = cursor++; i < addresses.length; i = cursor++) {
|
|
261
298
|
try {
|
|
262
|
-
results[i] = await diagnoseContract(addresses[i],
|
|
299
|
+
results[i] = await diagnoseContract(addresses[i], {
|
|
300
|
+
...options,
|
|
301
|
+
prefetched: { contract: contracts.get(addresses[i]) ?? null, config },
|
|
302
|
+
});
|
|
263
303
|
}
|
|
264
304
|
catch (e) {
|
|
265
305
|
// One unreadable contract must not kill a full scan. Report it as a
|
|
@@ -272,7 +312,7 @@ export async function diagnoseAllContracts(options = {}) {
|
|
|
272
312
|
healthy: false,
|
|
273
313
|
findings: [
|
|
274
314
|
{
|
|
275
|
-
code: '
|
|
315
|
+
code: 'diagnosisFailed',
|
|
276
316
|
severity: 'warning',
|
|
277
317
|
message: `Could not diagnose: ${e.message}`,
|
|
278
318
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../../../src/doctor/contract.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAgB,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAChF,OAAO,EAAE,gBAAgB,EAAe,MAAM,kCAAkC,CAAC;AACjF,OAAO,EACL,qBAAqB,EACrB,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,4BAA4B,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;AAEjE,2EAA2E;AAC3E,MAAM,iBAAiB,GAAG,kCAAkC,CAAC;AAE7D,0CAA0C;AAC1C,MAAM,kBAAkB,GAAG,CAAC,CAAC;AAE7B;;;;GAIG;AACH,MAAM,mBAAmB,GAAG,CAAC,CAAC,EAAE,CAAC,CAAU,CAAC;AAE5C;;;;GAIG;AACH,MAAM,qBAAqB,GAAG,QAAU,CAAC;AAEzC,2EAA2E;AAC3E,MAAM,wBAAwB,GAAG,MAAO,CAAC;AAiFzC,MAAM,MAAM,GAAG,gBAAgB,EAAE,CAAC;AAElC;;;;;;;;;;GAUG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAA0B;IAC3D,OAAO,iBAAiB,EAAE,CAAC,MAAM,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;AAC/D,CAAC;AAED,SAAS,YAAY,CACnB,IAAoD,EACpD,MAAgC;IAEhC,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACnD,IAAI,CAAC;QACH,OAAO,MAAM,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,eAAiC,EACjC,UAA2B,EAAE;IAE7B,MAAM,GAAG,GAAG,SAAS,CAAC,OAAO,CAAC,MAAM,IAAI,SAAS,EAAE,CAAC,CAAC;IACrD,MAAM,GAAG,GAAG,OAAO,CAAC,UAAU,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC;IACxE,MAAM,YAAY,GAAG,eAA0B,CAAC;IAEhD,yEAAyE;IACzE,qEAAqE;IACrE,iEAAiE;IACjE,MAAM,UAAU,GAAG,MAAM,YAAY,EAAE,CAAC;IACxC,MAAM,KAAK,GAAG,MAAM,GAAG;SACpB,mBAAmB,CAAC,CAAC,YAAY,EAAE,UAAU,CAAC,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;SACvE,IAAI,EAAE,CAAC;IACV,MAAM,QAAQ,GAAG,YAAY,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,EAAE,CAC1D,uBAAuB,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CACxC,CAAC;IACF,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAElG,MAAM,QAAQ,GAAsB,EAAE,CAAC;IACvC,MAAM,KAAK,GAAsB;QAC/B,QAAQ,EAAE,YAAY;QACtB,KAAK,EAAE,IAAI;QACX,KAAK,EAAE,IAAI;QACX,MAAM,EAAE,IAAI;QACZ,OAAO,EAAE,KAAK;QACd,QAAQ;QACR,aAAa,EAAE,EAAE;QACjB,MAAM,EAAE,EAAE,kBAAkB,EAAE,EAAE,EAAE,cAAc,EAAE,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE;QACxE,cAAc,EAAE,IAAI;QACpB,iBAAiB,EAAE,IAAI;KACxB,CAAC;IAEF,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,2EAA2E;QAC3E,mCAAmC;QACnC,MAAM,IAAI,KAAK,CAAC,oCAAoC,eAAe,EAAE,CAAC,CAAC;IACzE,CAAC;IAED,MAAM,MAAM,GAAmB;QAC7B,kBAAkB,EAAE,EAAE;QACtB,cAAc,EAAE,QAAQ,CAAC,cAAc;QACvC,YAAY,EAAE,QAAQ,CAAC,YAAY;KACpC,CAAC;IAEF,IAAI,QAAQ,CAAC,MAAM,KAAK,iBAAiB,EAAE,CAAC;QAC1C,QAAQ,CAAC,IAAI,CAAC;YACZ,IAAI,EAAE,qBAAqB;YAC3B,QAAQ,EAAE,SAAS;YACnB,OAAO,EAAE,gEAAgE;SAC1E,CAAC,CAAC;QACH,OAAO,EAAE,GAAG,KAAK,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAC3F,CAAC;IAED,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC;IAC/B,MAAM,eAAe,GAAG,QAAQ,CAAC,YAAY,KAAK,iBAAiB,CAAC;IAEpE,6EAA6E;IAC7E,sBAAsB;IACtB,MAAM,cAAc,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/F,MAAM,iBAAiB,GAAG,MAAM;QAC9B,CAAC,CAAC,MAAM,4BAA4B,CAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,SAAS,CAAC;QACtE,CAAC,CAAC,IAAI,CAAC;IACT,MAAM,KAAK,GAAc;QACvB,MAAM;QACN,GAAG,cAAc;QACjB,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACnD,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;KAClD,CAAC;IACF,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,mBAAmB,CAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAClF,MAAM,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC;IAC1C,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAC7D,MAAM,gBAAgB,GAAG,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACnF,MAAM,cAAc,GAAG,iBAAiB;QACtC,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,MAAM,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9D,CAAC,CAAC,IAAI,CAAC;IAET,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,QAAQ,CAAC,IAAI,CAAC;YACZ,IAAI,EAAE,eAAe;YACrB,QAAQ,EAAE,UAAU;YACpB,OAAO,EACL,UAAU,MAAM,2DAA2D;gBAC3E,uEAAuE;SAC1E,CAAC,CAAC;QACH,OAAO,EAAE,GAAG,KAAK,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IACpF,CAAC;IAED,MAAM,cAAc,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IACnD,MAAM,UAAU,GAAG,YAAY,CAAS,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,CAC/D,gBAAgB,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC,CAC9D,CAAC;IAEF,MAAM,aAAa,GAAa,EAAE,CAAC;IACnC,IAAI,UAAU,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC;QACzD,mBAAmB,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;YAC1C,0EAA0E;YAC1E,6DAA6D;YAC7D,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;gBAAE,OAAO;YAChC,IAAI,UAAU,CAAC,IAAI,CAAC;gBAAE,OAAO;YAC7B,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC1B,QAAQ,CAAC,IAAI,CAAC;gBACZ,IAAI,EAAE,cAAc;gBACpB,QAAQ,EAAE,UAAU;gBACpB,OAAO,EACL,uBAAuB,KAAK,QAAQ,cAAc,CAAC,IAAI,CAAC,mBAAmB;oBAC3E,iEAAiE;oBACjE,sEAAsE;gBACxE,UAAU,EAAE,KAAK;gBACjB,KAAK,EAAE,cAAc,CAAC,IAAI,CAAC;aAC5B,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,IAAI,UAAU,CAAC,MAAM,IAAI,eAAe,EAAE,CAAC;YACzC,QAAQ,CAAC,IAAI,CAAC;gBACZ,IAAI,EAAE,cAAc;gBACpB,QAAQ,EAAE,UAAU;gBACpB,OAAO,EAAE,sEAAsE;aAChF,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,IAAI,cAAc,GAAG,qBAAqB,EAAE,CAAC;QAC3C,QAAQ,CAAC,IAAI,CAAC;YACZ,IAAI,EAAE,mBAAmB;YACzB,QAAQ,EAAE,SAAS;YACnB,OAAO,EACL,gBAAgB,cAAc,wBAAwB,qBAAqB,SAAS;gBACpF,oFAAoF;SACvF,CAAC,CAAC;IACL,CAAC;IAED,IAAI,iBAAiB,IAAI,CAAC,cAAc,EAAE,CAAC;QACzC,yEAAyE;QACzE,0EAA0E;QAC1E,wEAAwE;QACxE,qCAAqC;QACrC,QAAQ,CAAC,IAAI,CAAC;YACZ,IAAI,EAAE,0BAA0B;YAChC,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS;YACnD,OAAO,EACL,yBAAyB,iBAAiB,+CAA+C;gBACzF,GAAG,QAAQ,CAAC,cAAc,wCAAwC;gBAClE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,0CAA0C,CAAC,CAAC,CAAC,EAAE,CAAC;gBACpE,mEAAmE;gBACnE,wDAAwD;SAC3D,CAAC,CAAC;IACL,CAAC;IAED,MAAM,YAAY,GAAG,gBAAgB;QACnC,CAAC,CAAC,YAAY,CAAC,gBAAgB,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACrF,CAAC,CAAC,IAAI,CAAC;IAET,IAAI,YAAY,EAAE,CAAC;QACjB,MAAM,CAAC,kBAAkB,GAAG,YAAY,CAAC,MAAM,CAAC;QAEhD,IAAI,YAAY,CAAC,OAAO,GAAG,GAAG,EAAE,CAAC;YAC/B,QAAQ,CAAC,IAAI,CAAC;gBACZ,IAAI,EAAE,eAAe;gBACrB,QAAQ,EAAE,UAAU;gBACpB,OAAO,EACL,uBAAuB,GAAG,GAAG,YAAY,CAAC,OAAO,iCAAiC;oBAClF,GAAG,YAAY,CAAC,MAAM,oCAAoC;aAC7D,CAAC,CAAC;QACL,CAAC;QACD,MAAM,MAAM,GAAG,GAAG,GAAG,YAAY,CAAC,WAAW,CAAC;QAC9C,IAAI,MAAM,GAAG,wBAAwB,IAAI,YAAY,CAAC,WAAW,GAAG,EAAE,EAAE,CAAC;YACvE,QAAQ,CAAC,IAAI,CAAC;gBACZ,IAAI,EAAE,mBAAmB;gBACzB,QAAQ,EAAE,UAAU;gBACpB,OAAO,EAAE,oCAAoC,MAAM,IAAI;aACxD,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO;QACL,QAAQ,EAAE,YAAY;QACtB,KAAK,EAAE,QAAQ,CAAC,KAAK;QACrB,KAAK,EAAE,QAAQ,CAAC,KAAK;QACrB,MAAM;QACN,OAAO,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,UAAU,CAAC;QACvD,QAAQ;QACR,aAAa;QACb,MAAM;QACN,cAAc;QACd,iBAAiB;KAClB,CAAC;AACJ,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,UAKI,EAAE;IAEN,MAAM,SAAS,GAAG,MAAM,yBAAyB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAClE,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC;IAC1D,MAAM,OAAO,GAAwB,IAAI,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACjE,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,IAAI,IAAI,GAAG,CAAC,CAAC;IAEb,KAAK,UAAU,MAAM;QACnB,KAAK,IAAI,CAAC,GAAG,MAAM,EAAE,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,GAAG,MAAM,EAAE,EAAE,CAAC;YAC1D,IAAI,CAAC;gBACH,OAAO,CAAC,CAAC,CAAC,GAAG,MAAM,gBAAgB,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;YAC7D,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,oEAAoE;gBACpE,wDAAwD;gBACxD,OAAO,CAAC,CAAC,CAAC,GAAG;oBACX,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC;oBACtB,KAAK,EAAE,IAAI;oBACX,KAAK,EAAE,IAAI;oBACX,MAAM,EAAE,IAAI;oBACZ,OAAO,EAAE,KAAK;oBACd,QAAQ,EAAE;wBACR;4BACE,IAAI,EAAE,qBAAqB;4BAC3B,QAAQ,EAAE,SAAS;4BACnB,OAAO,EAAE,uBAAwB,CAAW,CAAC,OAAO,EAAE;yBACvD;qBACF;oBACD,aAAa,EAAE,EAAE;oBACjB,MAAM,EAAE,EAAE,kBAAkB,EAAE,EAAE,EAAE,cAAc,EAAE,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE;oBACxE,cAAc,EAAE,IAAI;oBACpB,iBAAiB,EAAE,IAAI;iBACxB,CAAC;YACJ,CAAC;YACD,OAAO,CAAC,UAAU,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC;QACjD,CAAC;IACH,CAAC;IAED,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,SAAS,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC;IAC3F,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
1
|
+
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../../../src/doctor/contract.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,6 +4,10 @@ vi.mock('../utils/config', () => ({
|
|
|
4
4
|
}));
|
|
5
5
|
vi.mock('../utils/rpc', () => ({
|
|
6
6
|
createRpc: vi.fn(),
|
|
7
|
+
// Pass straight through: retry behaviour is covered in the rpc suite, and
|
|
8
|
+
// stubbing it out here would hide a call the diagnosis actually makes.
|
|
9
|
+
sendWithRetry: vi.fn((send) => send()),
|
|
10
|
+
MAX_MULTIPLE_ACCOUNTS: 100,
|
|
7
11
|
}));
|
|
8
12
|
vi.mock('../pda/thread', () => ({
|
|
9
13
|
deriveFiber: vi.fn(),
|
|
@@ -58,7 +62,7 @@ function setup(f = {}) {
|
|
|
58
62
|
decode: () => ({
|
|
59
63
|
owner: OWNER,
|
|
60
64
|
fleet: FLEET,
|
|
61
|
-
thread: THREAD,
|
|
65
|
+
thread: f.thread ?? THREAD,
|
|
62
66
|
activeRental: hasActiveRental ? ACTIVE_RENTAL : SYSTEM,
|
|
63
67
|
ownerClaimable: f.ownerClaimable ?? 500n,
|
|
64
68
|
feeClaimable: 10n,
|
|
@@ -72,7 +76,11 @@ function setup(f = {}) {
|
|
|
72
76
|
decode: () => ({ fiberIds: [0], paused: false, id: [] }),
|
|
73
77
|
});
|
|
74
78
|
vi.mocked(getRentalStateDecoder).mockReturnValue({
|
|
75
|
-
decode: () => ({
|
|
79
|
+
decode: () => ({
|
|
80
|
+
escrow: 1000n,
|
|
81
|
+
endTime: f.rentalEndTime ?? NOW + 86400n,
|
|
82
|
+
lastPayment: NOW - 60n,
|
|
83
|
+
}),
|
|
76
84
|
});
|
|
77
85
|
// The second batch answers by address rather than by position, so the
|
|
78
86
|
// diagnosis has to index its own probe correctly to read the right account.
|
|
@@ -138,4 +146,67 @@ describe('diagnoseContract — owner token account', () => {
|
|
|
138
146
|
expect(rpc.getMultipleAccounts).toHaveBeenCalledTimes(2);
|
|
139
147
|
});
|
|
140
148
|
});
|
|
149
|
+
describe('diagnoseContract — a contract with no thread is still diagnosed', () => {
|
|
150
|
+
// Bailing on `threadNotConfigured` used to end the diagnosis before the
|
|
151
|
+
// rental was read, and return `healthy: true` regardless.
|
|
152
|
+
it('reports the overdue rental it used to skip', async () => {
|
|
153
|
+
setup({ thread: SYSTEM, rentalEndTime: NOW - 3600n, present: [ACTIVE_RENTAL, OWNER_ATA] });
|
|
154
|
+
const dx = await diagnoseContract(CONTRACT, { nowSeconds: NOW });
|
|
155
|
+
const overdue = dx.findings.find(f => f.code === 'rentalOverdue');
|
|
156
|
+
expect(overdue).toBeDefined();
|
|
157
|
+
expect(overdue.severity).toBe('critical');
|
|
158
|
+
expect(dx.healthy).toBe(false);
|
|
159
|
+
});
|
|
160
|
+
it('carries the escrow still held, rather than reporting zero at risk', async () => {
|
|
161
|
+
setup({ thread: SYSTEM, rentalEndTime: NOW - 3600n, present: [ACTIVE_RENTAL, OWNER_ATA] });
|
|
162
|
+
const dx = await diagnoseContract(CONTRACT, { nowSeconds: NOW });
|
|
163
|
+
expect(dx.atRisk.activeRentalEscrow).toBe(1000n);
|
|
164
|
+
expect(dx.atRisk.ownerClaimable).toBe(500n);
|
|
165
|
+
});
|
|
166
|
+
it('flags a to_close contract with no thread as stranded', async () => {
|
|
167
|
+
setup({ thread: SYSTEM, toClose: true, present: [ACTIVE_RENTAL, OWNER_ATA] });
|
|
168
|
+
const dx = await diagnoseContract(CONTRACT, { nowSeconds: NOW });
|
|
169
|
+
const stranded = dx.findings.find(f => f.code === 'closeStranded');
|
|
170
|
+
expect(stranded).toBeDefined();
|
|
171
|
+
expect(stranded.severity).toBe('critical');
|
|
172
|
+
expect(stranded.message).toContain('Nothing will close the rental when it ends');
|
|
173
|
+
expect(dx.healthy).toBe(false);
|
|
174
|
+
});
|
|
175
|
+
it('says the close only needs running when the slot is already empty', async () => {
|
|
176
|
+
setup({ thread: SYSTEM, toClose: true, hasActiveRental: false, present: [OWNER_ATA] });
|
|
177
|
+
const dx = await diagnoseContract(CONTRACT, { nowSeconds: NOW });
|
|
178
|
+
const stranded = dx.findings.find(f => f.code === 'closeStranded');
|
|
179
|
+
expect(stranded.message).toContain('only needs running');
|
|
180
|
+
});
|
|
181
|
+
it('stays healthy when it is merely idle', async () => {
|
|
182
|
+
// No thread, no rental, not closing. Nothing is meant to happen, so a
|
|
183
|
+
// warning is the whole story — this must not become noise on every
|
|
184
|
+
// unautomated contract.
|
|
185
|
+
setup({ thread: SYSTEM, hasActiveRental: false, present: [OWNER_ATA] });
|
|
186
|
+
const dx = await diagnoseContract(CONTRACT, { nowSeconds: NOW });
|
|
187
|
+
expect(dx.findings.map(f => f.code)).toEqual(['threadNotConfigured']);
|
|
188
|
+
expect(dx.healthy).toBe(true);
|
|
189
|
+
});
|
|
190
|
+
it('probes only the accounts that exist for it', async () => {
|
|
191
|
+
// No thread means no thread account and no fibers in the batch. Indexing
|
|
192
|
+
// as though they were there reads the rental out of the wrong slot.
|
|
193
|
+
const rpc = setup({ thread: SYSTEM, present: [ACTIVE_RENTAL, OWNER_ATA] });
|
|
194
|
+
const dx = await diagnoseContract(CONTRACT, { nowSeconds: NOW });
|
|
195
|
+
expect(rpc.getMultipleAccounts.mock.calls[1][0]).toEqual([ACTIVE_RENTAL, OWNER_ATA]);
|
|
196
|
+
expect(dx.thread).toBeNull();
|
|
197
|
+
expect(dx.threadLamports).toBeNull();
|
|
198
|
+
expect(dx.findings.map(f => f.code)).not.toContain('ownerTokenAccountMissing');
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
describe('diagnoseContract — a thread that vanished is still diagnosed', () => {
|
|
202
|
+
it('reports both the missing thread and the overdue rental', async () => {
|
|
203
|
+
// `threadMissing` also used to return early, hiding everything after it.
|
|
204
|
+
setup({ rentalEndTime: NOW - 3600n, present: [ACTIVE_RENTAL, OWNER_ATA] });
|
|
205
|
+
const dx = await diagnoseContract(CONTRACT, { nowSeconds: NOW });
|
|
206
|
+
const codes = dx.findings.map(f => f.code);
|
|
207
|
+
expect(codes).toContain('threadMissing');
|
|
208
|
+
expect(codes).toContain('rentalOverdue');
|
|
209
|
+
expect(dx.atRisk.activeRentalEscrow).toBe(1000n);
|
|
210
|
+
});
|
|
211
|
+
});
|
|
141
212
|
//# sourceMappingURL=contract.test.js.map
|