@5ive-tech/sdk 1.1.2

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 (119) hide show
  1. package/README.md +279 -0
  2. package/dist/FiveSDK.d.ts +336 -0
  3. package/dist/FiveSDK.js +395 -0
  4. package/dist/accounts/index.d.ts +254 -0
  5. package/dist/accounts/index.js +543 -0
  6. package/dist/assets/vm/dummy.file +0 -0
  7. package/dist/assets/vm/five_vm_wasm.d.ts +762 -0
  8. package/dist/assets/vm/five_vm_wasm.js +3754 -0
  9. package/dist/assets/vm/five_vm_wasm_bg.js +3307 -0
  10. package/dist/assets/vm/five_vm_wasm_bg.wasm +0 -0
  11. package/dist/assets/vm/five_vm_wasm_bg.wasm.d.ts +247 -0
  12. package/dist/assets/vm/package.json +11 -0
  13. package/dist/bin/gen-types.d.ts +2 -0
  14. package/dist/bin/gen-types.js +35 -0
  15. package/dist/compiler/BytecodeCompiler.d.ts +83 -0
  16. package/dist/compiler/BytecodeCompiler.js +379 -0
  17. package/dist/config/ConfigManager.d.ts +13 -0
  18. package/dist/config/ConfigManager.js +27 -0
  19. package/dist/config/ProgramIdResolver.d.ts +62 -0
  20. package/dist/config/ProgramIdResolver.js +104 -0
  21. package/dist/crypto/index.d.ts +211 -0
  22. package/dist/crypto/index.js +451 -0
  23. package/dist/encoding/ParameterEncoder.d.ts +31 -0
  24. package/dist/encoding/ParameterEncoder.js +278 -0
  25. package/dist/index.d.ts +21 -0
  26. package/dist/index.js +28 -0
  27. package/dist/lib/bytecode-encoder.d.ts +62 -0
  28. package/dist/lib/bytecode-encoder.js +281 -0
  29. package/dist/logging/index.d.ts +9 -0
  30. package/dist/logging/index.js +10 -0
  31. package/dist/metadata/index.d.ts +213 -0
  32. package/dist/metadata/index.js +296 -0
  33. package/dist/modules/accounts.d.ts +60 -0
  34. package/dist/modules/accounts.js +275 -0
  35. package/dist/modules/deploy.d.ts +90 -0
  36. package/dist/modules/deploy.js +1118 -0
  37. package/dist/modules/execute.d.ts +90 -0
  38. package/dist/modules/execute.js +649 -0
  39. package/dist/modules/fees.d.ts +14 -0
  40. package/dist/modules/fees.js +112 -0
  41. package/dist/modules/namespaces.d.ts +39 -0
  42. package/dist/modules/namespaces.js +190 -0
  43. package/dist/modules/state-diff.d.ts +35 -0
  44. package/dist/modules/state-diff.js +342 -0
  45. package/dist/modules/vm-state.d.ts +7 -0
  46. package/dist/modules/vm-state.js +44 -0
  47. package/dist/program/AccountResolver.d.ts +67 -0
  48. package/dist/program/AccountResolver.js +134 -0
  49. package/dist/program/BorshSchemaGenerator.d.ts +8 -0
  50. package/dist/program/BorshSchemaGenerator.js +57 -0
  51. package/dist/program/FiveProgram.d.ts +144 -0
  52. package/dist/program/FiveProgram.js +282 -0
  53. package/dist/program/FunctionBuilder.d.ts +114 -0
  54. package/dist/program/FunctionBuilder.js +347 -0
  55. package/dist/program/ProgramAccount.d.ts +38 -0
  56. package/dist/program/ProgramAccount.js +170 -0
  57. package/dist/program/TypeGenerator.d.ts +90 -0
  58. package/dist/program/TypeGenerator.js +195 -0
  59. package/dist/program/index.d.ts +24 -0
  60. package/dist/program/index.js +21 -0
  61. package/dist/project/config.d.ts +5 -0
  62. package/dist/project/config.js +33 -0
  63. package/dist/project/toml.d.ts +6 -0
  64. package/dist/project/toml.js +43 -0
  65. package/dist/project/workspace.d.ts +160 -0
  66. package/dist/project/workspace.js +73 -0
  67. package/dist/testing/AccountMetaGenerator.d.ts +121 -0
  68. package/dist/testing/AccountMetaGenerator.js +261 -0
  69. package/dist/testing/AccountTestFixture.d.ts +211 -0
  70. package/dist/testing/AccountTestFixture.js +530 -0
  71. package/dist/testing/OnChainAccountManager.d.ts +81 -0
  72. package/dist/testing/OnChainAccountManager.js +260 -0
  73. package/dist/testing/StateSerializer.d.ts +65 -0
  74. package/dist/testing/StateSerializer.js +330 -0
  75. package/dist/testing/TestDiscovery.d.ts +79 -0
  76. package/dist/testing/TestDiscovery.js +274 -0
  77. package/dist/testing/TestRunner.d.ts +117 -0
  78. package/dist/testing/TestRunner.js +346 -0
  79. package/dist/testing/index.d.ts +14 -0
  80. package/dist/testing/index.js +13 -0
  81. package/dist/types.d.ts +356 -0
  82. package/dist/types.js +32 -0
  83. package/dist/utils/abi.d.ts +31 -0
  84. package/dist/utils/abi.js +92 -0
  85. package/dist/utils/transaction.d.ts +5 -0
  86. package/dist/utils/transaction.js +48 -0
  87. package/dist/validation/InputValidator.d.ts +142 -0
  88. package/dist/validation/InputValidator.js +332 -0
  89. package/dist/validation/index.d.ts +4 -0
  90. package/dist/validation/index.js +4 -0
  91. package/dist/wasm/compiler/AbiLogic.d.ts +4 -0
  92. package/dist/wasm/compiler/AbiLogic.js +37 -0
  93. package/dist/wasm/compiler/AnalysisLogic.d.ts +6 -0
  94. package/dist/wasm/compiler/AnalysisLogic.js +61 -0
  95. package/dist/wasm/compiler/CompilationLogic.d.ts +10 -0
  96. package/dist/wasm/compiler/CompilationLogic.js +431 -0
  97. package/dist/wasm/compiler/FiveCompiler.d.ts +48 -0
  98. package/dist/wasm/compiler/FiveCompiler.js +183 -0
  99. package/dist/wasm/compiler/InfoLogic.d.ts +6 -0
  100. package/dist/wasm/compiler/InfoLogic.js +24 -0
  101. package/dist/wasm/compiler/OptimizationLogic.d.ts +2 -0
  102. package/dist/wasm/compiler/OptimizationLogic.js +13 -0
  103. package/dist/wasm/compiler/ValidationLogic.d.ts +7 -0
  104. package/dist/wasm/compiler/ValidationLogic.js +26 -0
  105. package/dist/wasm/compiler/index.d.ts +2 -0
  106. package/dist/wasm/compiler/index.js +2 -0
  107. package/dist/wasm/compiler/types.d.ts +8 -0
  108. package/dist/wasm/compiler/types.js +1 -0
  109. package/dist/wasm/compiler/utils.d.ts +8 -0
  110. package/dist/wasm/compiler/utils.js +75 -0
  111. package/dist/wasm/index.d.ts +9 -0
  112. package/dist/wasm/index.js +12 -0
  113. package/dist/wasm/instance.d.ts +1 -0
  114. package/dist/wasm/instance.js +26 -0
  115. package/dist/wasm/loader.d.ts +7 -0
  116. package/dist/wasm/loader.js +112 -0
  117. package/dist/wasm/vm.d.ts +33 -0
  118. package/dist/wasm/vm.js +250 -0
  119. package/package.json +59 -0
@@ -0,0 +1,342 @@
1
+ import { executeOnSolana } from "./execute.js";
2
+ import { fetchMultipleAccountsAndDeserialize } from "./accounts.js";
3
+ import { PDAUtils } from "../crypto/index.js";
4
+ import { ProgramIdResolver } from "../config/ProgramIdResolver.js";
5
+ export async function executeWithStateDiff(scriptAccount, connection, signerKeypair, functionName, parameters = [], options = {}) {
6
+ const logs = [];
7
+ try {
8
+ if (options.debug) {
9
+ console.log(`[FiveSDK] Starting execution with state diff tracking`);
10
+ console.log(` Script Account: ${scriptAccount}`);
11
+ console.log(` Function: ${functionName}`);
12
+ console.log(` Parameters: ${JSON.stringify(parameters)}`);
13
+ console.log(` Track Global Fields: ${options.trackGlobalFields}`);
14
+ }
15
+ const accountsToTrack = [scriptAccount];
16
+ if (options.includeVMState) {
17
+ const programId = ProgramIdResolver.resolve(options.fiveVMProgramId);
18
+ const vmStatePDAResult = await PDAUtils.deriveVMStatePDA(programId);
19
+ const vmStatePDA = vmStatePDAResult.address;
20
+ accountsToTrack.push(vmStatePDA);
21
+ if (options.debug) {
22
+ console.log(` Added VM State PDA to tracking: ${vmStatePDA}`);
23
+ }
24
+ }
25
+ if (options.additionalAccounts) {
26
+ accountsToTrack.push(...options.additionalAccounts);
27
+ if (options.debug) {
28
+ console.log(` Added ${options.additionalAccounts.length} additional accounts to tracking`);
29
+ }
30
+ }
31
+ logs.push(`Tracking ${accountsToTrack.length} accounts for state changes`);
32
+ if (options.debug) {
33
+ console.log(`[FiveSDK] Fetching BEFORE state for ${accountsToTrack.length} accounts...`);
34
+ }
35
+ const beforeState = await fetchMultipleAccountsAndDeserialize(accountsToTrack, connection, {
36
+ debug: false,
37
+ parseMetadata: true,
38
+ validateEncoding: false,
39
+ });
40
+ let successfulBeforeFetches = 0;
41
+ for (const [address, result] of beforeState.entries()) {
42
+ if (result.success) {
43
+ successfulBeforeFetches++;
44
+ }
45
+ else if (options.debug) {
46
+ console.warn(`[FiveSDK] Warning: Failed to fetch BEFORE state for ${address}: ${result.error}`);
47
+ }
48
+ }
49
+ logs.push(`BEFORE state: ${successfulBeforeFetches}/${accountsToTrack.length} accounts fetched`);
50
+ let beforeGlobalFields = {};
51
+ if (options.trackGlobalFields) {
52
+ const scriptBefore = beforeState.get(scriptAccount);
53
+ if (scriptBefore?.success && scriptBefore.scriptMetadata) {
54
+ beforeGlobalFields = extractGlobalFields(scriptBefore.scriptMetadata, "before");
55
+ if (options.debug) {
56
+ console.log(`[FiveSDK] Extracted ${Object.keys(beforeGlobalFields).length} global fields from BEFORE state`);
57
+ }
58
+ }
59
+ }
60
+ if (options.debug) {
61
+ console.log(`[FiveSDK] Executing script...`);
62
+ }
63
+ const executionResult = await executeOnSolana(scriptAccount, connection, signerKeypair, functionName, parameters, options.additionalAccounts || [], {
64
+ debug: options.debug,
65
+ network: options.network,
66
+ computeUnitLimit: options.computeUnitLimit,
67
+ });
68
+ if (!executionResult.success) {
69
+ logs.push(`Execution failed: ${executionResult.error}`);
70
+ return {
71
+ success: false,
72
+ error: `Script execution failed: ${executionResult.error}`,
73
+ logs,
74
+ };
75
+ }
76
+ logs.push(`Execution successful: ${executionResult.transactionId}`);
77
+ await new Promise((resolve) => setTimeout(resolve, 1000));
78
+ if (options.debug) {
79
+ console.log(`[FiveSDK] Fetching AFTER state...`);
80
+ }
81
+ const afterState = await fetchMultipleAccountsAndDeserialize(accountsToTrack, connection, {
82
+ debug: false,
83
+ parseMetadata: true,
84
+ validateEncoding: false,
85
+ });
86
+ let successfulAfterFetches = 0;
87
+ for (const [address, result] of afterState.entries()) {
88
+ if (result.success) {
89
+ successfulAfterFetches++;
90
+ }
91
+ else if (options.debug) {
92
+ console.warn(`[FiveSDK] Warning: Failed to fetch AFTER state for ${address}: ${result.error}`);
93
+ }
94
+ }
95
+ logs.push(`AFTER state: ${successfulAfterFetches}/${accountsToTrack.length} accounts fetched`);
96
+ let afterGlobalFields = {};
97
+ if (options.trackGlobalFields) {
98
+ const scriptAfter = afterState.get(scriptAccount);
99
+ if (scriptAfter?.success && scriptAfter.scriptMetadata) {
100
+ afterGlobalFields = extractGlobalFields(scriptAfter.scriptMetadata, "after");
101
+ if (options.debug) {
102
+ console.log(`[FiveSDK] Extracted ${Object.keys(afterGlobalFields).length} global fields from AFTER state`);
103
+ }
104
+ }
105
+ }
106
+ if (options.debug) {
107
+ console.log(`[FiveSDK] Computing state differences...`);
108
+ }
109
+ const changes = computeStateDifferences(beforeState, afterState, options.debug);
110
+ let globalFieldChanges = [];
111
+ if (options.trackGlobalFields) {
112
+ globalFieldChanges = computeGlobalFieldChanges(beforeGlobalFields, afterGlobalFields);
113
+ if (options.debug) {
114
+ console.log(`[FiveSDK] Found ${globalFieldChanges.length} global field changes`);
115
+ }
116
+ }
117
+ logs.push(`State analysis: ${changes.length} account changes, ${globalFieldChanges.length} global field changes`);
118
+ return {
119
+ success: true,
120
+ execution: {
121
+ transactionId: executionResult.transactionId,
122
+ result: executionResult.result,
123
+ computeUnitsUsed: executionResult.computeUnitsUsed,
124
+ logs: executionResult.logs,
125
+ },
126
+ stateDiff: {
127
+ beforeState,
128
+ afterState,
129
+ changes,
130
+ globalFieldChanges,
131
+ },
132
+ logs,
133
+ };
134
+ }
135
+ catch (error) {
136
+ const errorMessage = error instanceof Error ? error.message : "Unknown state tracking error";
137
+ if (options.debug) {
138
+ console.error(`[FiveSDK] State diff execution failed: ${errorMessage}`);
139
+ }
140
+ return {
141
+ success: false,
142
+ error: errorMessage,
143
+ logs,
144
+ };
145
+ }
146
+ }
147
+ function computeStateDifferences(beforeState, afterState, debug = false) {
148
+ const changes = [];
149
+ const allAccounts = new Set([...beforeState.keys(), ...afterState.keys()]);
150
+ for (const account of allAccounts) {
151
+ const before = beforeState.get(account);
152
+ const after = afterState.get(account);
153
+ if (debug) {
154
+ console.log(`[FiveSDK] Analyzing account ${account.substring(0, 8)}...`);
155
+ }
156
+ if (!before?.success && after?.success) {
157
+ changes.push({
158
+ account,
159
+ oldValue: null,
160
+ newValue: {
161
+ lamports: after.accountInfo?.lamports,
162
+ dataLength: after.accountInfo?.dataLength,
163
+ owner: after.accountInfo?.owner,
164
+ },
165
+ changeType: "created",
166
+ });
167
+ continue;
168
+ }
169
+ if (before?.success && !after?.success) {
170
+ changes.push({
171
+ account,
172
+ oldValue: {
173
+ lamports: before.accountInfo?.lamports,
174
+ dataLength: before.accountInfo?.dataLength,
175
+ owner: before.accountInfo?.owner,
176
+ },
177
+ newValue: null,
178
+ changeType: "deleted",
179
+ });
180
+ continue;
181
+ }
182
+ if (before?.success && after?.success) {
183
+ if (before.accountInfo?.lamports !== after.accountInfo?.lamports) {
184
+ changes.push({
185
+ account,
186
+ fieldName: "lamports",
187
+ oldValue: before.accountInfo?.lamports,
188
+ newValue: after.accountInfo?.lamports,
189
+ changeType: "modified",
190
+ });
191
+ }
192
+ if (before.accountInfo?.dataLength !== after.accountInfo?.dataLength) {
193
+ changes.push({
194
+ account,
195
+ fieldName: "dataLength",
196
+ oldValue: before.accountInfo?.dataLength,
197
+ newValue: after.accountInfo?.dataLength,
198
+ changeType: "modified",
199
+ });
200
+ }
201
+ if (before.rawBytecode && after.rawBytecode) {
202
+ if (!bytecodeEqual(before.rawBytecode, after.rawBytecode)) {
203
+ changes.push({
204
+ account,
205
+ fieldName: "bytecode",
206
+ oldValue: `${before.rawBytecode.length} bytes (hash: ${hashBytecode(before.rawBytecode)})`,
207
+ newValue: `${after.rawBytecode.length} bytes (hash: ${hashBytecode(after.rawBytecode)})`,
208
+ changeType: "modified",
209
+ });
210
+ }
211
+ }
212
+ if (before.scriptMetadata && after.scriptMetadata) {
213
+ compareScriptMetadata(before.scriptMetadata, after.scriptMetadata, account, changes);
214
+ }
215
+ }
216
+ }
217
+ if (debug) {
218
+ console.log(`[FiveSDK] Found ${changes.length} total state changes`);
219
+ }
220
+ return changes;
221
+ }
222
+ function extractGlobalFields(scriptMetadata, phase) {
223
+ const globalFields = {};
224
+ try {
225
+ if (scriptMetadata.bytecode && scriptMetadata.bytecode.length > 6) {
226
+ const stateSection = extractStateSection(scriptMetadata.bytecode);
227
+ if (stateSection) {
228
+ Object.assign(globalFields, stateSection);
229
+ }
230
+ }
231
+ }
232
+ catch (error) {
233
+ console.warn(`[FiveSDK] Failed to extract global fields (${phase}):`, error);
234
+ }
235
+ return globalFields;
236
+ }
237
+ function computeGlobalFieldChanges(beforeFields, afterFields) {
238
+ const changes = [];
239
+ const allFields = new Set([
240
+ ...Object.keys(beforeFields),
241
+ ...Object.keys(afterFields),
242
+ ]);
243
+ for (const fieldName of allFields) {
244
+ const oldValue = beforeFields[fieldName];
245
+ const newValue = afterFields[fieldName];
246
+ if (!deepEqual(oldValue, newValue)) {
247
+ changes.push({
248
+ fieldName,
249
+ oldValue,
250
+ newValue,
251
+ });
252
+ }
253
+ }
254
+ return changes;
255
+ }
256
+ function compareScriptMetadata(beforeMetadata, afterMetadata, account, changes) {
257
+ if (beforeMetadata.abi.functions.length !== afterMetadata.abi.functions.length) {
258
+ changes.push({
259
+ account,
260
+ fieldName: "function_count",
261
+ oldValue: beforeMetadata.abi.functions.length,
262
+ newValue: afterMetadata.abi.functions.length,
263
+ changeType: "modified",
264
+ });
265
+ }
266
+ if (beforeMetadata.abi.name !== afterMetadata.abi.name) {
267
+ changes.push({
268
+ account,
269
+ fieldName: "script_name",
270
+ oldValue: beforeMetadata.abi.name,
271
+ newValue: afterMetadata.abi.name,
272
+ changeType: "modified",
273
+ });
274
+ }
275
+ if (beforeMetadata.authority !== afterMetadata.authority) {
276
+ changes.push({
277
+ account,
278
+ fieldName: "authority",
279
+ oldValue: beforeMetadata.authority,
280
+ newValue: afterMetadata.authority,
281
+ changeType: "modified",
282
+ });
283
+ }
284
+ }
285
+ function extractStateSection(bytecode) {
286
+ try {
287
+ if (bytecode.length < 6)
288
+ return null;
289
+ const stateMarker = new Uint8Array([0xff, 0xfe]);
290
+ for (let i = 6; i < bytecode.length - 1; i++) {
291
+ if (bytecode[i] === stateMarker[0] &&
292
+ bytecode[i + 1] === stateMarker[1]) {
293
+ const stateData = {};
294
+ return stateData;
295
+ }
296
+ }
297
+ }
298
+ catch (error) {
299
+ console.warn("[FiveSDK] State section extraction failed:", error);
300
+ }
301
+ return null;
302
+ }
303
+ function bytecodeEqual(a, b) {
304
+ if (a.length !== b.length)
305
+ return false;
306
+ for (let i = 0; i < a.length; i++) {
307
+ if (a[i] !== b[i])
308
+ return false;
309
+ }
310
+ return true;
311
+ }
312
+ function hashBytecode(bytecode) {
313
+ let hash = 0;
314
+ for (let i = 0; i < bytecode.length; i++) {
315
+ hash = ((hash << 5) - hash + bytecode[i]) & 0xffffffff;
316
+ }
317
+ return hash.toString(16);
318
+ }
319
+ function deepEqual(a, b) {
320
+ if (a === b)
321
+ return true;
322
+ if (a == null || b == null)
323
+ return false;
324
+ if (typeof a !== typeof b)
325
+ return false;
326
+ if (typeof a === "object") {
327
+ if (Array.isArray(a) !== Array.isArray(b))
328
+ return false;
329
+ const keysA = Object.keys(a);
330
+ const keysB = Object.keys(b);
331
+ if (keysA.length !== keysB.length)
332
+ return false;
333
+ for (const key of keysA) {
334
+ if (!keysB.includes(key))
335
+ return false;
336
+ if (!deepEqual(a[key], b[key]))
337
+ return false;
338
+ }
339
+ return true;
340
+ }
341
+ return false;
342
+ }
@@ -0,0 +1,7 @@
1
+ export declare function getVMState(connection: any, fiveVMProgramId?: string): Promise<{
2
+ authority: string;
3
+ scriptCount: number;
4
+ deployFeeBps: number;
5
+ executeFeeBps: number;
6
+ isInitialized: boolean;
7
+ }>;
@@ -0,0 +1,44 @@
1
+ import { PDAUtils, Base58Utils } from "../crypto/index.js";
2
+ import { ProgramIdResolver } from "../config/ProgramIdResolver.js";
3
+ export async function getVMState(connection, fiveVMProgramId) {
4
+ const programId = ProgramIdResolver.resolve(fiveVMProgramId);
5
+ const vmStatePDA = await PDAUtils.deriveVMStatePDA(programId);
6
+ let accountData;
7
+ try {
8
+ if (typeof connection.getAccountInfo === 'function') {
9
+ let pubkey = vmStatePDA.address;
10
+ try {
11
+ const { PublicKey } = await import("@solana/web3.js");
12
+ pubkey = new PublicKey(vmStatePDA.address);
13
+ }
14
+ catch { }
15
+ const info = await connection.getAccountInfo(pubkey);
16
+ if (!info)
17
+ throw new Error("VM State account not found");
18
+ accountData = new Uint8Array(info.data);
19
+ }
20
+ else if (typeof connection.getAccountData === 'function') {
21
+ const info = await connection.getAccountData(vmStatePDA.address);
22
+ if (!info)
23
+ throw new Error("VM State account not found");
24
+ accountData = new Uint8Array(info.data);
25
+ }
26
+ else {
27
+ throw new Error("Invalid connection object: must support getAccountInfo or getAccountData");
28
+ }
29
+ if (accountData.length < 56)
30
+ throw new Error(`VM State account data too small: expected 56, got ${accountData.length}`);
31
+ const authority = Base58Utils.encode(accountData.slice(0, 32));
32
+ const view = new DataView(accountData.buffer, accountData.byteOffset, accountData.byteLength);
33
+ return {
34
+ authority,
35
+ scriptCount: Number(view.getBigUint64(32, true)),
36
+ deployFeeBps: view.getUint32(40, true),
37
+ executeFeeBps: view.getUint32(44, true),
38
+ isInitialized: accountData[48] === 1
39
+ };
40
+ }
41
+ catch (error) {
42
+ throw new Error(`Failed to fetch VM state: ${error instanceof Error ? error.message : "Unknown error"}`);
43
+ }
44
+ }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * AccountResolver - Automatic system account injection
3
+ *
4
+ * Intelligently adds system accounts based on function constraints:
5
+ * - @init constraint → adds SystemProgram
6
+ * - Other constraints may add Rent, Clock, etc. (future)
7
+ *
8
+ * This reduces boilerplate by eliminating the need for developers to
9
+ * manually pass system accounts for every function call.
10
+ */
11
+ import type { FunctionDefinition, ParameterDefinition, ScriptABI } from '../metadata/index.js';
12
+ import type { FiveProgramOptions } from './FiveProgram.js';
13
+ import type { FiveProgram } from './FiveProgram.js';
14
+ export interface ResolvedSystemAccounts {
15
+ [accountName: string]: string;
16
+ }
17
+ /**
18
+ * AccountResolver handles automatic injection of system accounts
19
+ */
20
+ export declare class AccountResolver {
21
+ private options;
22
+ constructor(options: FiveProgramOptions);
23
+ /**
24
+ * Resolve system accounts that should be auto-injected
25
+ * Detects @init constraints and adds SystemProgram if needed
26
+ *
27
+ * @param funcDef - Function definition from ABI
28
+ * @param providedAccounts - Accounts already provided by user
29
+ * @returns Map of system account names to their addresses
30
+ */
31
+ resolveSystemAccounts(funcDef: FunctionDefinition, providedAccounts: Map<string, string>): ResolvedSystemAccounts;
32
+ /**
33
+ * Resolve PDA accounts based on ABI constraints
34
+ *
35
+ * @param abi - Script ABI containing account constraints
36
+ * @param providedAccounts - Currently known accounts (user provided + system)
37
+ * @param program - FiveProgram instance for derivation util
38
+ */
39
+ resolvePdaAccounts(abi: ScriptABI, providedAccounts: Map<string, string>, program: FiveProgram): Promise<ResolvedSystemAccounts>;
40
+ /**
41
+ * Check if function has @init constraint on any parameter
42
+ * @init means account creation via CPI
43
+ *
44
+ * @param funcDef - Function definition
45
+ * @returns true if any parameter has @init attribute
46
+ */
47
+ private hasInitConstraint;
48
+ /**
49
+ * Get account metadata from parameter attributes
50
+ * Maps Five DSL attributes to Solana account properties
51
+ *
52
+ * @param param - Parameter definition
53
+ * @returns Object with isSigner and isWritable flags
54
+ */
55
+ getAccountMetadata(param: ParameterDefinition): {
56
+ isSigner: boolean;
57
+ isWritable: boolean;
58
+ };
59
+ /**
60
+ * Validate that all required accounts are provided after resolution
61
+ *
62
+ * @param funcDef - Function definition
63
+ * @param allAccounts - All accounts (user-provided + system-injected)
64
+ * @throws Error if required account is missing
65
+ */
66
+ validateResolvedAccounts(funcDef: FunctionDefinition, allAccounts: Map<string, string>): void;
67
+ }
@@ -0,0 +1,134 @@
1
+ /**
2
+ * AccountResolver - Automatic system account injection
3
+ *
4
+ * Intelligently adds system accounts based on function constraints:
5
+ * - @init constraint → adds SystemProgram
6
+ * - Other constraints may add Rent, Clock, etc. (future)
7
+ *
8
+ * This reduces boilerplate by eliminating the need for developers to
9
+ * manually pass system accounts for every function call.
10
+ */
11
+ // Known system program IDs (Solana standard)
12
+ const SYSTEM_PROGRAM_ID = '11111111111111111111111111111111';
13
+ /**
14
+ * AccountResolver handles automatic injection of system accounts
15
+ */
16
+ export class AccountResolver {
17
+ constructor(options) {
18
+ this.options = options;
19
+ }
20
+ /**
21
+ * Resolve system accounts that should be auto-injected
22
+ * Detects @init constraints and adds SystemProgram if needed
23
+ *
24
+ * @param funcDef - Function definition from ABI
25
+ * @param providedAccounts - Accounts already provided by user
26
+ * @returns Map of system account names to their addresses
27
+ */
28
+ resolveSystemAccounts(funcDef, providedAccounts) {
29
+ const systemAccounts = {};
30
+ // Check if function has @init constraint
31
+ const hasInit = this.hasInitConstraint(funcDef);
32
+ if (hasInit && !providedAccounts.has('systemProgram')) {
33
+ systemAccounts['systemProgram'] = SYSTEM_PROGRAM_ID;
34
+ if (this.options.debug) {
35
+ console.log(`[AccountResolver] Auto-injecting SystemProgram for @init constraint`);
36
+ }
37
+ }
38
+ return systemAccounts;
39
+ }
40
+ /**
41
+ * Resolve PDA accounts based on ABI constraints
42
+ *
43
+ * @param abi - Script ABI containing account constraints
44
+ * @param providedAccounts - Currently known accounts (user provided + system)
45
+ * @param program - FiveProgram instance for derivation util
46
+ */
47
+ async resolvePdaAccounts(abi, providedAccounts, program) {
48
+ const pdaAccounts = {};
49
+ if (!abi.accounts)
50
+ return pdaAccounts;
51
+ // Filter for PDA constraints
52
+ const pdaConstraints = abi.accounts.filter(acc => acc.type === 'pda');
53
+ for (const constraint of pdaConstraints) {
54
+ if (providedAccounts.has(constraint.name)) {
55
+ continue; // User already provided it
56
+ }
57
+ // Resolve seeds
58
+ const seeds = [];
59
+ let canResolve = true;
60
+ for (const seed of (constraint.seeds || [])) {
61
+ if (seed.startsWith('"') && seed.endsWith('"')) {
62
+ // Static string seed: "my_seed"
63
+ seeds.push(seed.slice(1, -1));
64
+ }
65
+ else {
66
+ // Dynamic seed: account reference
67
+ const refAddr = providedAccounts.get(seed);
68
+ if (refAddr) {
69
+ seeds.push(refAddr);
70
+ }
71
+ else {
72
+ // Dependency missing; single-pass resolution only.
73
+ canResolve = false;
74
+ break;
75
+ }
76
+ }
77
+ }
78
+ if (canResolve && seeds.length > 0) {
79
+ try {
80
+ const [pda] = await program.findAddress(seeds);
81
+ pdaAccounts[constraint.name] = pda;
82
+ if (this.options.debug) {
83
+ console.log(`[AccountResolver] Auto-derived PDA '${constraint.name}': ${pda}`);
84
+ }
85
+ }
86
+ catch (e) {
87
+ console.warn(`[AccountResolver] Failed to derive PDA '${constraint.name}':`, e);
88
+ }
89
+ }
90
+ }
91
+ return pdaAccounts;
92
+ }
93
+ /**
94
+ * Check if function has @init constraint on any parameter
95
+ * @init means account creation via CPI
96
+ *
97
+ * @param funcDef - Function definition
98
+ * @returns true if any parameter has @init attribute
99
+ */
100
+ hasInitConstraint(funcDef) {
101
+ return funcDef.parameters.some((param) => {
102
+ const attributes = param.attributes || [];
103
+ return attributes.includes('init');
104
+ });
105
+ }
106
+ /**
107
+ * Get account metadata from parameter attributes
108
+ * Maps Five DSL attributes to Solana account properties
109
+ *
110
+ * @param param - Parameter definition
111
+ * @returns Object with isSigner and isWritable flags
112
+ */
113
+ getAccountMetadata(param) {
114
+ const attributes = param.attributes || [];
115
+ return {
116
+ isSigner: attributes.includes('signer'),
117
+ isWritable: attributes.includes('mut') || attributes.includes('init'),
118
+ };
119
+ }
120
+ /**
121
+ * Validate that all required accounts are provided after resolution
122
+ *
123
+ * @param funcDef - Function definition
124
+ * @param allAccounts - All accounts (user-provided + system-injected)
125
+ * @throws Error if required account is missing
126
+ */
127
+ validateResolvedAccounts(funcDef, allAccounts) {
128
+ for (const param of funcDef.parameters) {
129
+ if (param.is_account && !allAccounts.has(param.name)) {
130
+ throw new Error(`Required account '${param.name}' not provided and not auto-injected`);
131
+ }
132
+ }
133
+ }
134
+ }
@@ -0,0 +1,8 @@
1
+ import { ScriptABI, TypeDefinition } from '../metadata/index.js';
2
+ export declare class BorshSchemaGenerator {
3
+ private abi;
4
+ constructor(abi: ScriptABI);
5
+ generate(typeDef: TypeDefinition): Map<Function, any>;
6
+ private processType;
7
+ private mapType;
8
+ }
@@ -0,0 +1,57 @@
1
+ export class BorshSchemaGenerator {
2
+ constructor(abi) {
3
+ this.abi = abi;
4
+ }
5
+ generate(typeDef) {
6
+ const map = new Map();
7
+ this.processType(typeDef, map);
8
+ return map;
9
+ }
10
+ processType(typeDef, map) {
11
+ // Dynamic class creation for the schema
12
+ const StructClass = function () { };
13
+ Object.defineProperty(StructClass, 'name', { value: typeDef.name });
14
+ if (typeDef.structure === 'struct') {
15
+ const fields = typeDef.fields?.map(field => {
16
+ return [field.name, this.mapType(field.type)];
17
+ });
18
+ map.set(StructClass, { kind: 'struct', fields });
19
+ }
20
+ else if (typeDef.structure === 'enum') {
21
+ // Enum handling
22
+ const values = typeDef.variants?.map(v => {
23
+ // Safe cast or optional access as v matches structure
24
+ // Based on metadata definition, variants have { name, value? } but not explicit 'fields' in interface?
25
+ // We will map simple scalar enums
26
+ return [v.name, undefined];
27
+ });
28
+ map.set(StructClass, { kind: 'enum', values });
29
+ }
30
+ }
31
+ mapType(type) {
32
+ switch (type) {
33
+ case 'u8': return 'u8';
34
+ case 'u16': return 'u16';
35
+ case 'u32': return 'u32';
36
+ case 'u64': return 'u64';
37
+ case 'u128': return 'u128';
38
+ case 'i8': return 'i8';
39
+ case 'i16': return 'i16';
40
+ case 'i32': return 'i32';
41
+ case 'i64': return 'i64';
42
+ case 'i128': return 'i128';
43
+ case 'bool': return 'u8'; // Borsh standard for bool
44
+ case 'string': return 'string';
45
+ case 'pubkey': return [32]; // Fixed array of 32 bytes
46
+ default:
47
+ // Handle vectors: Vec<T>
48
+ if (type.startsWith('Vec<')) {
49
+ const inner = type.slice(4, -1);
50
+ return [this.mapType(inner)];
51
+ }
52
+ // Handle arrays: [T; N]
53
+ // Handle option: Option<T>
54
+ return type; // Assume it's a known struct name
55
+ }
56
+ }
57
+ }