@5ive-tech/sdk 1.1.10 → 1.1.13

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 (36) hide show
  1. package/README.md +1 -1
  2. package/dist/FiveSDK.d.ts +3 -4
  3. package/dist/FiveSDK.js +47 -5
  4. package/dist/accounts/index.js +3 -2
  5. package/dist/assets/vm/five_vm_wasm_bg.wasm +0 -0
  6. package/dist/assets/vm/five_vm_wasm_bg.wasm.d.ts +5 -5
  7. package/dist/bin/gen-types.js +0 -0
  8. package/dist/compiler/BytecodeCompiler.d.ts +1 -7
  9. package/dist/compiler/BytecodeCompiler.js +105 -44
  10. package/dist/config/ProgramIdResolver.d.ts +1 -6
  11. package/dist/config/ProgramIdResolver.js +11 -16
  12. package/dist/config/VmClusterConfigResolver.d.ts +27 -0
  13. package/dist/config/VmClusterConfigResolver.js +111 -0
  14. package/dist/index.d.ts +1 -1
  15. package/dist/index.js +1 -1
  16. package/dist/modules/accounts.js +7 -1
  17. package/dist/modules/admin.js +25 -12
  18. package/dist/modules/deploy.js +62 -23
  19. package/dist/modules/execute.js +71 -37
  20. package/dist/modules/vm-state.js +6 -1
  21. package/dist/program/FunctionBuilder.d.ts +8 -0
  22. package/dist/program/FunctionBuilder.js +18 -5
  23. package/dist/project/config.js +0 -1
  24. package/dist/testing/TestRunner.js +6 -1
  25. package/dist/types.d.ts +19 -2
  26. package/dist/utils/abi.d.ts +4 -0
  27. package/dist/utils/abi.js +3 -0
  28. package/dist/utils/transaction.d.ts +22 -0
  29. package/dist/utils/transaction.js +94 -12
  30. package/dist/wasm/compiler/CompilationLogic.d.ts +0 -5
  31. package/dist/wasm/compiler/CompilationLogic.js +45 -163
  32. package/dist/wasm/compiler/FiveCompiler.d.ts +0 -5
  33. package/dist/wasm/compiler/FiveCompiler.js +0 -6
  34. package/dist/wasm/compiler/utils.d.ts +34 -1
  35. package/dist/wasm/compiler/utils.js +223 -5
  36. package/package.json +4 -3
package/README.md CHANGED
@@ -13,7 +13,7 @@ npm install @5ive-tech/sdk @solana/web3.js
13
13
  ### 1) Compile to `.five`
14
14
 
15
15
  ```bash
16
- 5ive compile src/main.v -o build/my-program.five
16
+ 5ive build
17
17
  ```
18
18
 
19
19
  ### 1b) Compile directly with SDK (optional)
package/dist/FiveSDK.d.ts CHANGED
@@ -98,10 +98,7 @@ export declare class FiveSDK {
98
98
  static compile(source: FiveScriptSource | string, options?: CompilationOptions & {
99
99
  debug?: boolean;
100
100
  }): Promise<CompilationResult>;
101
- static compileModules(mainSource: FiveScriptSource | string, modules: Array<{
102
- name: string;
103
- source: string;
104
- }>, options?: CompilationOptions & {
101
+ static compileProject(projectPath?: string, options?: CompilationOptions & {
105
102
  debug?: boolean;
106
103
  }): Promise<CompilationResult>;
107
104
  static compileWithDiscovery(entryPoint: string, options?: CompilationOptions & {
@@ -175,6 +172,8 @@ export declare class FiveSDK {
175
172
  isWritable: boolean;
176
173
  isSystemAccount?: boolean;
177
174
  }>;
175
+ feeShardIndex?: number;
176
+ payerAccount?: string;
178
177
  }): Promise<SerializedExecution>;
179
178
  static getVMState(connection: any, fiveVMProgramId?: string): Promise<{
180
179
  authority: string;
package/dist/FiveSDK.js CHANGED
@@ -1,6 +1,8 @@
1
1
  /**
2
2
  * Five SDK client for Five VM scripts.
3
3
  */
4
+ import { dirname, isAbsolute, join, resolve, } from "path";
5
+ import { readFile, } from "fs/promises";
4
6
  import { FiveSDKError, } from "./types.js";
5
7
  import { BytecodeCompiler } from "./compiler/BytecodeCompiler.js";
6
8
  import { ParameterEncoder } from "./encoding/ParameterEncoder.js";
@@ -16,6 +18,8 @@ import * as Accounts from "./modules/accounts.js";
16
18
  import * as StateDiff from "./modules/state-diff.js";
17
19
  import * as Namespaces from "./modules/namespaces.js";
18
20
  import * as Admin from "./modules/admin.js";
21
+ import { parseToml } from "./project/toml.js";
22
+ import { parseProjectConfig } from "./project/config.js";
19
23
  /**
20
24
  * Main Five SDK class - entry point for all Five VM interactions
21
25
  */
@@ -130,7 +134,11 @@ export class FiveSDK {
130
134
  parameters: func.parameters?.map((param) => ({
131
135
  name: param.name,
132
136
  type: param.type,
137
+ param_type: param.param_type,
133
138
  optional: param.optional ?? false,
139
+ is_account: param.is_account ?? param.isAccount ?? false,
140
+ isAccount: param.isAccount ?? param.is_account ?? false,
141
+ attributes: Array.isArray(param.attributes) ? [...param.attributes] : [],
134
142
  })) || [],
135
143
  returnType: func.returnType,
136
144
  }));
@@ -155,16 +163,50 @@ export class FiveSDK {
155
163
  return result;
156
164
  }
157
165
  catch (error) {
158
- throw new FiveSDKError(`Compilation failed: ${error instanceof Error ? error.message : "Unknown error"}`, "COMPILATION_ERROR");
166
+ if (error instanceof FiveSDKError) {
167
+ throw error;
168
+ }
169
+ const inheritedDetails = error && typeof error === "object" && error.details
170
+ ? error.details
171
+ : undefined;
172
+ throw new FiveSDKError(`Compilation failed: ${error instanceof Error ? error.message : "Unknown error"}`, "COMPILATION_ERROR", {
173
+ ...(inheritedDetails || {}),
174
+ cause: error instanceof Error ? error.message : String(error),
175
+ });
159
176
  }
160
177
  }
161
- static async compileModules(mainSource, modules, options = {}) {
162
- const mainSourceObj = typeof mainSource === 'string' ? { content: mainSource, filename: 'main.v' } : mainSource;
178
+ static async compileProject(projectPath = process.cwd(), options = {}) {
163
179
  Validators.options(options);
164
180
  await this.initializeComponents(options.debug);
165
- if (!this.compiler)
181
+ if (!this.compiler) {
166
182
  throw new FiveSDKError("Compiler not initialized", "COMPILER_ERROR");
167
- return this.compiler.compileModules(mainSourceObj, modules, options);
183
+ }
184
+ const normalizedProjectPath = isAbsolute(projectPath)
185
+ ? projectPath
186
+ : resolve(process.cwd(), projectPath);
187
+ const configPath = normalizedProjectPath.endsWith(".toml")
188
+ ? normalizedProjectPath
189
+ : join(normalizedProjectPath, "five.toml");
190
+ const rootDir = dirname(configPath);
191
+ const rawToml = await readFile(configPath, "utf8");
192
+ const parsed = parseToml(rawToml);
193
+ const projectConfig = parseProjectConfig(parsed);
194
+ if (!projectConfig.entryPoint) {
195
+ throw new FiveSDKError(`Missing required project.entry_point in ${configPath}`, "PROJECT_CONFIG_ERROR");
196
+ }
197
+ const entryPoint = isAbsolute(projectConfig.entryPoint)
198
+ ? projectConfig.entryPoint
199
+ : resolve(rootDir, projectConfig.entryPoint);
200
+ return this.compiler.compileWithDiscovery(entryPoint, {
201
+ ...options,
202
+ target: options.target || projectConfig.target || "vm",
203
+ optimizationLevel: options.optimizationLevel ||
204
+ projectConfig.optimizations?.optimizationLevel ||
205
+ "production",
206
+ includeMetrics: options.includeMetrics,
207
+ metricsFormat: options.metricsFormat || "json",
208
+ errorFormat: options.errorFormat || "terminal",
209
+ });
168
210
  }
169
211
  static async compileWithDiscovery(entryPoint, options = {}) {
170
212
  Validators.options(options);
@@ -5,6 +5,7 @@
5
5
  * and account size calculations. Uses serialization instead of direct blockchain calls.
6
6
  */
7
7
  import { PDAUtils, SolanaPublicKeyUtils, RentCalculator, AccountValidator } from '../crypto/index.js';
8
+ import { ProgramIdResolver } from '../config/ProgramIdResolver.js';
8
9
  /**
9
10
  * AccountType enum for test compatibility
10
11
  */
@@ -22,8 +23,8 @@ export const AccountType = {
22
23
  * Account manager for Five VM scripts (serialization-based)
23
24
  */
24
25
  export class FiveAccountManager {
25
- constructor(programId = 'FiveProgramID11111111111111111111111111111') {
26
- this.programId = programId;
26
+ constructor(programId) {
27
+ this.programId = ProgramIdResolver.resolve(programId);
27
28
  }
28
29
  /**
29
30
  * Encode System Program CreateAccount instruction
Binary file
@@ -227,19 +227,19 @@ export const bytecodeencoder_encoded_size_u32: (a: number) => number;
227
227
  export const bytecodeencoder_encoded_size_u16: (a: number) => number;
228
228
  export const parameterencoder_encode_execute: (a: number, b: number, c: number) => void;
229
229
  export const get_wasm_compiler_info: () => number;
230
+ export const __wbg_set_wasmsuggestion_confidence: (a: number, b: number) => void;
231
+ export const __wbg_set_wasmenhancedcompilationresult_compilation_time: (a: number, b: number) => void;
232
+ export const __wbg_set_wasmcompilationwithmetrics_compilation_time: (a: number, b: number) => void;
233
+ export const __wbg_set_wasmcompilationresult_compilation_time: (a: number, b: number) => void;
230
234
  export const __wbg_get_wasmsuggestion_confidence: (a: number) => number;
231
235
  export const __wbg_get_wasmenhancedcompilationresult_compilation_time: (a: number) => number;
232
236
  export const __wbg_get_wasmcompilationwithmetrics_compilation_time: (a: number) => number;
233
237
  export const __wbg_get_wasmcompilationresult_compilation_time: (a: number) => number;
234
238
  export const __wbg_set_wasmenhancedcompilationresult_success: (a: number, b: number) => void;
235
239
  export const __wbg_get_wasmenhancedcompilationresult_success: (a: number) => number;
236
- export const __wbg_set_wasmsuggestion_confidence: (a: number, b: number) => void;
237
- export const __wbg_set_wasmenhancedcompilationresult_compilation_time: (a: number, b: number) => void;
238
- export const __wbg_set_wasmcompilationwithmetrics_compilation_time: (a: number, b: number) => void;
239
- export const __wbg_set_wasmcompilationresult_compilation_time: (a: number, b: number) => void;
240
240
  export const __wbg_wasmfivecompiler_free: (a: number, b: number) => void;
241
- export const __wbg_parameterencoder_free: (a: number, b: number) => void;
242
241
  export const __wbg_bytecodeencoder_free: (a: number, b: number) => void;
242
+ export const __wbg_parameterencoder_free: (a: number, b: number) => void;
243
243
  export const __wbindgen_export: (a: number, b: number) => number;
244
244
  export const __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;
245
245
  export const __wbindgen_export3: (a: number) => void;
File without changes
@@ -26,13 +26,7 @@ export declare class BytecodeCompiler {
26
26
  * Compile Five script source to bytecode
27
27
  */
28
28
  compile(source: FiveScriptSource | string, options?: CompilationOptions): Promise<CompilationResult>;
29
- /**
30
- * Compile multiple modules (entry + dependencies)
31
- */
32
- compileModules(mainSource: FiveScriptSource, modules: Array<{
33
- name: string;
34
- source: string;
35
- }>, options?: CompilationOptions): Promise<CompilationResult>;
29
+ compileWithDiscovery(entryPoint: string, options?: CompilationOptions): Promise<CompilationResult>;
36
30
  /**
37
31
  * Compile script from file path
38
32
  */
@@ -39,6 +39,7 @@ export class BytecodeCompiler {
39
39
  debug: options.debug || false,
40
40
  maxSize: options.maxSize || 1048576, // 1MB default
41
41
  optimizationLevel: options.optimizationLevel || "production", // Default to Production
42
+ sourceFile: sourceFilename,
42
43
  // Pass through metrics options
43
44
  metricsFormat: options.metricsFormat,
44
45
  metricsOutput: options.metricsOutput,
@@ -87,7 +88,7 @@ export class BytecodeCompiler {
87
88
  };
88
89
  }
89
90
  else {
90
- const errors = this.transformErrors(result.errors || []);
91
+ const errors = this.transformErrors(result.diagnostics || result.errors || []);
91
92
  if (this.debug) {
92
93
  console.log(`[BytecodeCompiler] Compilation failed with ${errors.length} errors`);
93
94
  errors.forEach((error) => {
@@ -97,74 +98,96 @@ export class BytecodeCompiler {
97
98
  return {
98
99
  success: false,
99
100
  errors,
101
+ diagnostics: errors,
102
+ formattedErrorsTerminal: result.formattedErrorsTerminal,
103
+ formattedErrorsJson: result.formattedErrorsJson,
100
104
  metricsReport: result.metricsReport,
101
105
  };
102
106
  }
103
107
  }
104
108
  catch (error) {
105
- throw new CompilationSDKError(`Compilation error: ${error instanceof Error ? error.message : "Unknown error"}`, { source: sourceContent.substring(0, 200), options });
109
+ if (error instanceof CompilationSDKError) {
110
+ throw error;
111
+ }
112
+ const inheritedDetails = error && typeof error === "object" && error.details
113
+ ? error.details
114
+ : undefined;
115
+ throw new CompilationSDKError(`Compilation error: ${error instanceof Error ? error.message : "Unknown error"}`, {
116
+ ...(inheritedDetails || {}),
117
+ source: sourceContent.substring(0, 200),
118
+ options,
119
+ });
106
120
  }
107
121
  }
108
- /**
109
- * Compile multiple modules (entry + dependencies)
110
- */
111
- async compileModules(mainSource, modules, options = {}) {
122
+ async compileWithDiscovery(entryPoint, options = {}) {
112
123
  const startTime = Date.now();
113
124
  try {
114
125
  if (!this.wasmCompiler) {
115
126
  await this.loadWasmCompiler();
116
127
  }
117
- if (!this.wasmCompiler?.compile_multi) {
118
- throw new CompilationSDKError("Multi-file compilation is not supported in this build");
128
+ if (!this.wasmCompiler?.compileWithDiscovery) {
129
+ throw new CompilationSDKError("Compiler discovery API is not supported in this build");
119
130
  }
120
- const compilerOptions = {
121
- optimize: options.optimize || false,
122
- target: options.target || "vm",
123
- debug: options.debug || false,
124
- maxSize: options.maxSize || 1048576,
125
- optimizationLevel: options.optimizationLevel || "production",
126
- includeMetrics: options.includeMetrics || options.metricsOutput !== undefined,
127
- metricsFormat: options.metricsFormat || "json",
128
- errorFormat: options.errorFormat || "terminal",
129
- comprehensiveMetrics: options.comprehensiveMetrics || false,
130
- };
131
- const result = await this.wasmCompiler.compile_multi(mainSource.content, modules, compilerOptions);
131
+ const result = await this.wasmCompiler.compileWithDiscovery(entryPoint, {
132
+ ...options,
133
+ sourceFile: entryPoint,
134
+ });
132
135
  const compilationTime = Date.now() - startTime;
133
136
  if (result.success && result.bytecode) {
134
137
  const compilerInfo = await this.getCompilerInfo();
138
+ let abiData = result.abi;
139
+ if (!abiData) {
140
+ abiData = await this.generateABI(typeof entryPoint === 'string' ? await readFile(entryPoint, 'utf8') : entryPoint);
141
+ }
142
+ const normalizedFunctions = normalizeAbiFunctions(abiData?.functions ?? abiData);
143
+ const normalizedAbi = {
144
+ ...abiData,
145
+ functions: normalizedFunctions,
146
+ };
135
147
  return {
136
148
  success: true,
137
149
  bytecode: result.bytecode,
138
- abi: result.abi,
150
+ abi: normalizedAbi,
139
151
  disassembly: result.disassembly || [],
140
152
  metadata: {
141
- sourceFile: mainSource.filename || 'main.v',
153
+ sourceFile: entryPoint,
142
154
  timestamp: new Date().toISOString(),
143
- compilerVersion: compilerInfo.version || '1.0.0',
144
- target: (options.target || 'vm'),
155
+ compilerVersion: compilerInfo.version || "1.0.0",
156
+ target: (options.target || "vm"),
145
157
  optimizations: [],
146
- originalSize: mainSource.content.length,
158
+ originalSize: 0,
147
159
  compressedSize: result.bytecode.length,
148
160
  compressionRatio: 1.0,
149
- sourceSize: mainSource.content.length,
161
+ sourceSize: 0,
150
162
  bytecodeSize: result.bytecode.length,
151
- functions: [],
163
+ functions: this.extractFunctions(normalizedAbi),
152
164
  compilationTime,
153
165
  },
154
166
  metricsReport: result.metricsReport,
155
167
  };
156
168
  }
157
- else {
158
- const errors = this.transformErrors(result.errors || result.compiler_errors || []);
159
- return {
160
- success: false,
161
- errors,
162
- metricsReport: result.metricsReport,
163
- };
164
- }
169
+ const errors = this.transformErrors(result.diagnostics || result.errors || []);
170
+ return {
171
+ success: false,
172
+ errors,
173
+ diagnostics: errors,
174
+ formattedErrorsTerminal: result.formattedErrorsTerminal,
175
+ formattedErrorsJson: result.formattedErrorsJson,
176
+ metricsReport: result.metricsReport,
177
+ };
165
178
  }
166
179
  catch (error) {
167
- throw new CompilationSDKError(`Compilation error: ${error instanceof Error ? error.message : "Unknown error"}`, { options });
180
+ if (error instanceof CompilationSDKError) {
181
+ throw error;
182
+ }
183
+ const inheritedDetails = error && typeof error === "object" && error.details
184
+ ? error.details
185
+ : undefined;
186
+ throw new CompilationSDKError(`Compilation error: ${error instanceof Error ? error.message : "Unknown error"}`, {
187
+ ...(inheritedDetails || {}),
188
+ entryPoint,
189
+ options,
190
+ });
168
191
  }
169
192
  }
170
193
  /**
@@ -176,7 +199,13 @@ export class BytecodeCompiler {
176
199
  }
177
200
  try {
178
201
  const source = await readFile(filePath, "utf-8");
179
- return this.compile(source, options);
202
+ return this.compile({
203
+ filename: filePath,
204
+ content: source,
205
+ }, {
206
+ ...options,
207
+ sourceFile: filePath,
208
+ });
180
209
  }
181
210
  catch (error) {
182
211
  throw new CompilationSDKError(`Failed to read file ${filePath}: ${error instanceof Error ? error.message : "Unknown error"}`, { filePath, options });
@@ -282,13 +311,45 @@ export class BytecodeCompiler {
282
311
  * Transform compiler errors to SDK format
283
312
  */
284
313
  transformErrors(errors) {
285
- return errors.map((error) => ({
286
- type: 'compiler',
287
- message: error.message || error.toString(),
288
- line: error.line,
289
- column: error.column,
290
- severity: error.severity || "error",
291
- }));
314
+ return errors.map((error) => {
315
+ const normalized = typeof error === "string" ? { message: error } : (error || {});
316
+ const location = normalized.location || {};
317
+ const lineValue = normalized.line ?? location.line;
318
+ const columnValue = normalized.column ?? location.column;
319
+ const line = typeof lineValue === "number"
320
+ ? lineValue
321
+ : typeof lineValue === "string"
322
+ ? Number(lineValue)
323
+ : undefined;
324
+ const column = typeof columnValue === "number"
325
+ ? columnValue
326
+ : typeof columnValue === "string"
327
+ ? Number(columnValue)
328
+ : undefined;
329
+ return {
330
+ type: normalized.type || "compiler",
331
+ message: normalized.message || String(error),
332
+ line: Number.isFinite(line) ? line : undefined,
333
+ column: Number.isFinite(column) ? column : undefined,
334
+ severity: normalized.severity || "error",
335
+ code: normalized.code,
336
+ category: normalized.category,
337
+ description: normalized.description,
338
+ location: normalized.location,
339
+ sourceLocation: normalized.sourceLocation || location.file,
340
+ suggestion: normalized.suggestion ||
341
+ (Array.isArray(normalized.suggestions) && normalized.suggestions.length > 0
342
+ ? typeof normalized.suggestions[0] === "string"
343
+ ? normalized.suggestions[0]
344
+ : normalized.suggestions[0]?.message
345
+ : undefined),
346
+ suggestions: normalized.suggestions,
347
+ sourceLine: normalized.sourceLine || normalized.source_line,
348
+ sourceSnippet: normalized.sourceSnippet || normalized.source_snippet,
349
+ rendered: normalized.rendered,
350
+ raw: normalized.raw || error,
351
+ };
352
+ });
292
353
  }
293
354
  /**
294
355
  * Extract function definitions from ABI
@@ -1,12 +1,7 @@
1
1
  /**
2
2
  * Centralized program ID resolution for Five SDK.
3
- * Implements consistent precedence: explicit → default → env baked → error
3
+ * Implements strict precedence: explicit → SDK default → cluster config → error
4
4
  */
5
- /**
6
- * Baked program ID injected at release time (set by scripts/set-default-program-id.sh)
7
- * Empty string by default; overridden in npm published packages.
8
- */
9
- export declare const FIVE_BAKED_PROGRAM_ID = "4Qxf3pbCse2veUgZVMiAm3nWqJrYo2pT4suxHKMJdK1d";
10
5
  /**
11
6
  * Centralized resolver for program IDs across all SDK operations.
12
7
  * Ensures consistent validation and error messaging.
@@ -1,13 +1,9 @@
1
1
  /**
2
2
  * Centralized program ID resolution for Five SDK.
3
- * Implements consistent precedence: explicit → default → env baked → error
3
+ * Implements strict precedence: explicit → SDK default → cluster config → error
4
4
  */
5
5
  import { validator } from '../validation/index.js';
6
- /**
7
- * Baked program ID injected at release time (set by scripts/set-default-program-id.sh)
8
- * Empty string by default; overridden in npm published packages.
9
- */
10
- export const FIVE_BAKED_PROGRAM_ID = '4Qxf3pbCse2veUgZVMiAm3nWqJrYo2pT4suxHKMJdK1d';
6
+ import { VmClusterConfigResolver } from './VmClusterConfigResolver.js';
11
7
  /**
12
8
  * Centralized resolver for program IDs across all SDK operations.
13
9
  * Ensures consistent validation and error messaging.
@@ -49,8 +45,7 @@ export class ProgramIdResolver {
49
45
  * ```
50
46
  */
51
47
  static resolve(explicit, options) {
52
- // Precedence: explicit → default → env → baked
53
- // Note: Must check for explicit empty string differently from undefined
48
+ // Precedence: explicit → default → cluster-config
54
49
  let resolved;
55
50
  if (explicit) {
56
51
  resolved = explicit;
@@ -58,20 +53,20 @@ export class ProgramIdResolver {
58
53
  else if (this.defaultProgramId) {
59
54
  resolved = this.defaultProgramId;
60
55
  }
61
- else if (process.env.FIVE_PROGRAM_ID) {
62
- resolved = process.env.FIVE_PROGRAM_ID;
63
- }
64
- else if (FIVE_BAKED_PROGRAM_ID) {
65
- resolved = FIVE_BAKED_PROGRAM_ID;
56
+ else {
57
+ try {
58
+ resolved = VmClusterConfigResolver.loadClusterConfig().programId;
59
+ }
60
+ catch {
61
+ resolved = undefined;
62
+ }
66
63
  }
67
64
  if (!resolved && !options?.allowUndefined) {
68
65
  throw new Error(`No program ID resolved for Five VM. ` +
69
66
  `Set via one of: ` +
70
67
  `(1) explicit call parameter, ` +
71
68
  `(2) FiveSDK.setDefaultProgramId(), ` +
72
- `(3) FIVE_PROGRAM_ID environment variable, ` +
73
- `(4) released package default. ` +
74
- `For setup guidance, see: https://docs.five.build/cli/program-id-setup`);
69
+ `(3) five-solana/constants.vm.toml cluster profile.`);
75
70
  }
76
71
  if (resolved) {
77
72
  validator.validateBase58Address(resolved, 'programId');
@@ -0,0 +1,27 @@
1
+ export interface VmClusterProfile {
2
+ cluster: 'localnet' | 'devnet' | 'mainnet';
3
+ configPath: string;
4
+ programId: string;
5
+ feeVaultShardCount: number;
6
+ }
7
+ export interface VmClusterAddresses {
8
+ cluster: VmClusterProfile['cluster'];
9
+ programId: string;
10
+ feeVaultShardCount: number;
11
+ vmStatePda: string;
12
+ vmStateBump: number;
13
+ feeVaultPdas: Array<{
14
+ shardIndex: number;
15
+ address: string;
16
+ bump: number;
17
+ }>;
18
+ }
19
+ export declare class VmClusterConfigResolver {
20
+ static resolveClusterFromEnvOrDefault(): VmClusterProfile['cluster'];
21
+ static getDefaultConfigPath(): string;
22
+ static loadClusterConfig(input?: {
23
+ cluster?: string;
24
+ configPath?: string;
25
+ }): VmClusterProfile;
26
+ static deriveVmAddresses(profile: VmClusterProfile): VmClusterAddresses;
27
+ }
@@ -0,0 +1,111 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { PublicKey } from '@solana/web3.js';
4
+ const VM_STATE_SEED = Buffer.from('vm_state', 'utf-8');
5
+ const FEE_VAULT_SEED = Buffer.from([
6
+ 0xff, 0x66, 0x69, 0x76, 0x65, 0x5f, 0x76, 0x6d, 0x5f, 0x66, 0x65, 0x65,
7
+ 0x5f, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x76, 0x31,
8
+ ]);
9
+ const VALID_CLUSTERS = new Set(['localnet', 'devnet', 'mainnet']);
10
+ function resolveDefaultConfigPath() {
11
+ if (process.env.FIVE_VM_CONSTANTS_CONFIG) {
12
+ return path.resolve(process.env.FIVE_VM_CONSTANTS_CONFIG);
13
+ }
14
+ const candidates = [
15
+ path.resolve(process.cwd(), 'five-solana/constants.vm.toml'),
16
+ path.resolve(process.cwd(), '../five-solana/constants.vm.toml'),
17
+ ];
18
+ for (const candidate of candidates) {
19
+ if (fs.existsSync(candidate)) {
20
+ return candidate;
21
+ }
22
+ }
23
+ return candidates[0];
24
+ }
25
+ function parseSimpleVmToml(raw) {
26
+ const clusters = {};
27
+ let current = null;
28
+ for (const lineRaw of raw.split('\n')) {
29
+ const line = lineRaw.trim();
30
+ if (!line || line.startsWith('#'))
31
+ continue;
32
+ const sec = line.match(/^\[clusters\.(localnet|devnet|mainnet)\]$/);
33
+ if (sec) {
34
+ current = sec[1];
35
+ clusters[current] = {};
36
+ continue;
37
+ }
38
+ if (!current)
39
+ continue;
40
+ const kv = line.match(/^([a-z_]+)\s*=\s*(.+)$/);
41
+ if (!kv)
42
+ continue;
43
+ const key = kv[1];
44
+ const rawVal = kv[2].trim();
45
+ if (rawVal.startsWith('"') && rawVal.endsWith('"')) {
46
+ clusters[current][key] = rawVal.slice(1, -1);
47
+ }
48
+ else if (/^\d+$/.test(rawVal)) {
49
+ clusters[current][key] = Number(rawVal);
50
+ }
51
+ else {
52
+ throw new Error(`Unsupported TOML value: ${line}`);
53
+ }
54
+ }
55
+ return { clusters };
56
+ }
57
+ export class VmClusterConfigResolver {
58
+ static resolveClusterFromEnvOrDefault() {
59
+ const cluster = (process.env.FIVE_VM_CLUSTER || 'localnet').trim();
60
+ if (!VALID_CLUSTERS.has(cluster)) {
61
+ throw new Error(`Invalid FIVE_VM_CLUSTER: ${cluster} (expected localnet|devnet|mainnet)`);
62
+ }
63
+ return cluster;
64
+ }
65
+ static getDefaultConfigPath() {
66
+ return resolveDefaultConfigPath();
67
+ }
68
+ static loadClusterConfig(input = {}) {
69
+ const cluster = (input.cluster || this.resolveClusterFromEnvOrDefault()).trim();
70
+ if (!VALID_CLUSTERS.has(cluster)) {
71
+ throw new Error(`Invalid cluster: ${cluster}`);
72
+ }
73
+ const configPath = path.resolve(input.configPath || this.getDefaultConfigPath());
74
+ if (!fs.existsSync(configPath)) {
75
+ throw new Error(`VM constants config not found: ${configPath}`);
76
+ }
77
+ const parsed = parseSimpleVmToml(fs.readFileSync(configPath, 'utf-8'));
78
+ const entry = parsed.clusters?.[cluster];
79
+ if (!entry)
80
+ throw new Error(`Cluster missing in VM constants config: ${cluster}`);
81
+ if (!entry.program_id)
82
+ throw new Error(`Missing program_id for cluster ${cluster}`);
83
+ if (!Number.isInteger(entry.fee_vault_shard_count) || entry.fee_vault_shard_count < 1) {
84
+ throw new Error(`Invalid fee_vault_shard_count for cluster ${cluster}`);
85
+ }
86
+ const programId = new PublicKey(entry.program_id).toBase58();
87
+ return {
88
+ cluster: cluster,
89
+ configPath,
90
+ programId,
91
+ feeVaultShardCount: entry.fee_vault_shard_count,
92
+ };
93
+ }
94
+ static deriveVmAddresses(profile) {
95
+ const programPk = new PublicKey(profile.programId);
96
+ const [vmStatePda, vmStateBump] = PublicKey.findProgramAddressSync([VM_STATE_SEED], programPk);
97
+ const feeVaultPdas = [];
98
+ for (let i = 0; i < profile.feeVaultShardCount; i++) {
99
+ const [vault, bump] = PublicKey.findProgramAddressSync([FEE_VAULT_SEED, Buffer.from([i])], programPk);
100
+ feeVaultPdas.push({ shardIndex: i, address: vault.toBase58(), bump });
101
+ }
102
+ return {
103
+ cluster: profile.cluster,
104
+ programId: profile.programId,
105
+ feeVaultShardCount: profile.feeVaultShardCount,
106
+ vmStatePda: vmStatePda.toBase58(),
107
+ vmStateBump,
108
+ feeVaultPdas,
109
+ };
110
+ }
111
+ }
package/dist/index.d.ts CHANGED
@@ -17,5 +17,5 @@ export * from './wasm/loader.js';
17
17
  export * from './testing/index.js';
18
18
  export * from './program/index.js';
19
19
  export * from './modules/namespaces.js';
20
- export { ProgramIdResolver, FIVE_BAKED_PROGRAM_ID } from './config/ProgramIdResolver.js';
20
+ export { ProgramIdResolver } from './config/ProgramIdResolver.js';
21
21
  export { FIVE_VM_PROGRAM_ID } from './types.js';
package/dist/index.js CHANGED
@@ -21,7 +21,7 @@ export * from './testing/index.js';
21
21
  export * from './program/index.js';
22
22
  export * from './modules/namespaces.js';
23
23
  // ==================== Program ID Resolution ====================
24
- export { ProgramIdResolver, FIVE_BAKED_PROGRAM_ID } from './config/ProgramIdResolver.js';
24
+ export { ProgramIdResolver } from './config/ProgramIdResolver.js';
25
25
  // ==================== Constants ====================
26
26
  export { FIVE_VM_PROGRAM_ID } from './types.js';
27
27
  // Default export disabled for minimal build
@@ -2,6 +2,7 @@ import { ScriptMetadataParser } from "../metadata/index.js";
2
2
  import { normalizeAbiFunctions } from "../utils/abi.js";
3
3
  import { loadWasmVM } from "../wasm/instance.js";
4
4
  import { SolanaPublicKeyUtils } from "../crypto/index.js";
5
+ import { getAccountInfoWithRetry } from "../utils/transaction.js";
5
6
  export async function fetchAccountAndDeserialize(accountAddress, connection, // Solana Connection object
6
7
  options = {}) {
7
8
  try {
@@ -27,7 +28,12 @@ options = {}) {
27
28
  logs: [],
28
29
  };
29
30
  }
30
- const accountInfo = await connection.getAccountInfo(accountPubkey, "confirmed");
31
+ const accountInfo = await getAccountInfoWithRetry(connection, accountPubkey, {
32
+ commitment: "finalized",
33
+ retries: 2,
34
+ delayMs: 1000,
35
+ debug: options.debug,
36
+ });
31
37
  if (!accountInfo) {
32
38
  return {
33
39
  success: false,