@5ive-tech/sdk 1.1.13 → 1.1.15

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 (44) hide show
  1. package/README.md +22 -0
  2. package/dist/FiveSDK.d.ts +43 -1
  3. package/dist/FiveSDK.js +6 -0
  4. package/dist/accounts/index.d.ts +10 -28
  5. package/dist/accounts/index.js +33 -61
  6. package/dist/assets/vm/five_vm_wasm.d.ts +8 -0
  7. package/dist/assets/vm/five_vm_wasm.js +25 -0
  8. package/dist/assets/vm/five_vm_wasm_bg.wasm +0 -0
  9. package/dist/assets/vm/five_vm_wasm_bg.wasm.d.ts +3 -0
  10. package/dist/bin/gen-types.js +0 -0
  11. package/dist/compiler/BytecodeCompiler.js +10 -6
  12. package/dist/compiler/source-normalization.d.ts +1 -0
  13. package/dist/compiler/source-normalization.js +67 -0
  14. package/dist/config/ProgramIdResolver.js +6 -2
  15. package/dist/constants/headers.d.ts +2 -0
  16. package/dist/constants/headers.js +2 -0
  17. package/dist/crypto/index.d.ts +8 -1
  18. package/dist/crypto/index.js +27 -14
  19. package/dist/index.d.ts +1 -0
  20. package/dist/index.js +1 -0
  21. package/dist/modules/accounts.js +1 -1
  22. package/dist/modules/deploy.js +167 -98
  23. package/dist/modules/execute.d.ts +5 -0
  24. package/dist/modules/execute.js +109 -50
  25. package/dist/modules/fees.js +2 -2
  26. package/dist/modules/namespaces.d.ts +11 -0
  27. package/dist/modules/namespaces.js +64 -0
  28. package/dist/program/FiveProgram.js +4 -3
  29. package/dist/program/TypeGenerator.js +8 -1
  30. package/dist/project/config.js +113 -1
  31. package/dist/project/workspace.d.ts +5 -0
  32. package/dist/testing/AccountTestFixture.js +3 -3
  33. package/dist/testing/TestDiscovery.d.ts +1 -0
  34. package/dist/testing/TestDiscovery.js +18 -2
  35. package/dist/testing/TestRunner.js +4 -1
  36. package/dist/types.d.ts +17 -6
  37. package/dist/types.js +2 -1
  38. package/dist/utils/abi.js +33 -10
  39. package/dist/utils/transaction.d.ts +16 -0
  40. package/dist/utils/transaction.js +81 -5
  41. package/dist/wasm/compiler/CompilationLogic.js +3 -3
  42. package/dist/wasm/vm.d.ts +2 -2
  43. package/dist/wasm/vm.js +10 -11
  44. package/package.json +1 -1
@@ -1,9 +1,10 @@
1
1
  import { PDAUtils, RentCalculator } from "../crypto/index.js";
2
2
  import { validator, Validators } from "../validation/index.js";
3
3
  import { calculateDeployFee } from "./fees.js";
4
- import { confirmTransactionRobust, getAccountInfoWithRetry, pollForConfirmation, SDK_COMMITMENTS, } from "../utils/transaction.js";
4
+ import { getAccountInfoWithRetry, sendAndConfirmRawTransactionRobust, SDK_COMMITMENTS, } from "../utils/transaction.js";
5
5
  import { ProgramIdResolver } from "../config/ProgramIdResolver.js";
6
6
  import { VmClusterConfigResolver } from "../config/VmClusterConfigResolver.js";
7
+ import { SCRIPT_ACCOUNT_HEADER_LEN } from "../constants/headers.js";
7
8
  const DEFAULT_FEE_VAULT_SHARD_COUNT = (() => {
8
9
  try {
9
10
  return VmClusterConfigResolver.loadClusterConfig().feeVaultShardCount;
@@ -12,13 +13,28 @@ const DEFAULT_FEE_VAULT_SHARD_COUNT = (() => {
12
13
  return 2;
13
14
  }
14
15
  })();
16
+ const MAX_FEE_VAULT_SHARD_COUNT = 8;
15
17
  const FEE_VAULT_NAMESPACE_SEED = Buffer.from([
16
18
  0xff, 0x66, 0x69, 0x76, 0x65, 0x5f, 0x76, 0x6d, 0x5f, 0x66, 0x65, 0x65,
17
19
  0x5f, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x76, 0x31,
18
20
  ]);
19
21
  function clampShardCount(rawCount) {
20
22
  const normalized = rawCount > 0 ? rawCount : DEFAULT_FEE_VAULT_SHARD_COUNT;
21
- return Math.max(1, Math.min(DEFAULT_FEE_VAULT_SHARD_COUNT, normalized));
23
+ return Math.max(1, Math.min(MAX_FEE_VAULT_SHARD_COUNT, normalized));
24
+ }
25
+ function normalizeRpcEndpoint(connection) {
26
+ return String(connection?.rpcEndpoint || connection?._rpcEndpoint || "").toLowerCase();
27
+ }
28
+ function isLocalnetBootstrapConnection(connection, network) {
29
+ const normalizedNetwork = String(network || "").toLowerCase();
30
+ if (normalizedNetwork === "localnet") {
31
+ return true;
32
+ }
33
+ const endpoint = normalizeRpcEndpoint(connection);
34
+ return endpoint.includes("127.0.0.1") || endpoint.includes("localhost");
35
+ }
36
+ function selectBootstrapCommitment(connection, network) {
37
+ return isLocalnetBootstrapConnection(connection, network) ? "confirmed" : "finalized";
22
38
  }
23
39
  async function readVMStateFeeConfig(connection, vmStateAddress) {
24
40
  if (!connection) {
@@ -53,6 +69,25 @@ async function deriveProgramFeeVault(programId, shardIndex) {
53
69
  const [pda, bump] = PublicKey.findProgramAddressSync([FEE_VAULT_NAMESPACE_SEED, Buffer.from([shardIndex])], new PublicKey(programId));
54
70
  return { address: pda.toBase58(), bump };
55
71
  }
72
+ async function resolveScriptAccountDerivation(bytecode, deployer, programId, options) {
73
+ const { PublicKey } = await import("@solana/web3.js");
74
+ if (options.scriptAccount) {
75
+ validator.validateBase58Address(options.scriptAccount, "options.scriptAccount");
76
+ if (!options.scriptSeed) {
77
+ throw new Error("options.scriptSeed is required when options.scriptAccount is provided");
78
+ }
79
+ const expectedAccount = await PublicKey.createWithSeed(new PublicKey(deployer), options.scriptSeed, new PublicKey(programId));
80
+ if (expectedAccount.toBase58() !== options.scriptAccount) {
81
+ throw new Error("options.scriptAccount does not match the derived address for the provided deployer, scriptSeed, and programId");
82
+ }
83
+ return {
84
+ address: options.scriptAccount,
85
+ bump: 0,
86
+ seed: options.scriptSeed,
87
+ };
88
+ }
89
+ return PDAUtils.deriveScriptAccount(bytecode, deployer, programId);
90
+ }
56
91
  function createInitFeeVaultInstructionData(shardIndex, bump) {
57
92
  return Uint8Array.from([11, shardIndex & 0xff, bump & 0xff]);
58
93
  }
@@ -60,10 +95,24 @@ async function initProgramFeeVaultShards(connection, programId, vmStateAccount,
60
95
  const { PublicKey, Transaction, TransactionInstruction, SystemProgram } = await import("@solana/web3.js");
61
96
  const signatures = [];
62
97
  const effectiveShardCount = clampShardCount(shardCount);
98
+ const programPubkey = new PublicKey(programId);
99
+ const bootstrapCommitment = selectBootstrapCommitment(connection);
63
100
  for (let shardIndex = 0; shardIndex < effectiveShardCount; shardIndex++) {
64
101
  const vault = await deriveProgramFeeVault(programId, shardIndex);
102
+ const existingVault = await getAccountInfoWithRetry(connection, new PublicKey(vault.address), {
103
+ commitment: bootstrapCommitment,
104
+ retries: 1,
105
+ delayMs: 500,
106
+ debug: options.debug,
107
+ });
108
+ if (existingVault?.owner && new PublicKey(existingVault.owner).equals(programPubkey)) {
109
+ if (options.debug) {
110
+ console.log(`[FiveSDK] Fee vault shard ${shardIndex} already initialized: ${vault.address}`);
111
+ }
112
+ continue;
113
+ }
65
114
  const tx = new Transaction().add(new TransactionInstruction({
66
- programId: new PublicKey(programId),
115
+ programId: programPubkey,
67
116
  keys: [
68
117
  { pubkey: new PublicKey(vmStateAccount), isSigner: false, isWritable: false },
69
118
  { pubkey: payer.publicKey, isSigner: true, isWritable: true },
@@ -72,24 +121,24 @@ async function initProgramFeeVaultShards(connection, programId, vmStateAccount,
72
121
  ],
73
122
  data: Buffer.from(createInitFeeVaultInstructionData(shardIndex, vault.bump)),
74
123
  }));
75
- const { blockhash } = await connection.getLatestBlockhash("confirmed");
76
- tx.recentBlockhash = blockhash;
124
+ const latestBlockhash = await connection.getLatestBlockhash("confirmed");
125
+ tx.recentBlockhash = latestBlockhash.blockhash;
77
126
  tx.feePayer = payer.publicKey;
78
127
  tx.partialSign(payer);
79
- const sig = await connection.sendRawTransaction(tx.serialize(), {
80
- skipPreflight: true,
81
- preflightCommitment: "confirmed",
82
- maxRetries: options.maxRetries || 3,
83
- });
84
- const shardConfirm = await confirmTransactionRobust(connection, sig, {
85
- commitment: "finalized",
128
+ const shardSend = await sendAndConfirmRawTransactionRobust(connection, tx.serialize(), {
129
+ commitment: bootstrapCommitment,
86
130
  timeoutMs: 120000,
87
131
  debug: options.debug,
132
+ maxRetries: options.maxRetries || 3,
133
+ skipPreflight: false,
134
+ preflightCommitment: "confirmed",
135
+ blockhash: latestBlockhash.blockhash,
136
+ lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
88
137
  });
89
- if (!shardConfirm.success) {
90
- throw new Error(`Fee vault shard init failed: ${shardConfirm.error || "unconfirmed"}`);
138
+ if (!shardSend.success || !shardSend.signature) {
139
+ throw new Error(`Fee vault shard init failed: ${shardSend.error || "unconfirmed"}`);
91
140
  }
92
- signatures.push(sig);
141
+ signatures.push(shardSend.signature);
93
142
  if (options.debug) {
94
143
  console.log(`[FiveSDK] Initialized fee vault shard ${shardIndex}: ${vault.address}`);
95
144
  }
@@ -100,9 +149,6 @@ export async function generateDeployInstruction(bytecode, deployer, options = {}
100
149
  Validators.bytecode(bytecode);
101
150
  validator.validateBase58Address(deployer, "deployer");
102
151
  Validators.options(options);
103
- if (options.scriptAccount) {
104
- validator.validateBase58Address(options.scriptAccount, "options.scriptAccount");
105
- }
106
152
  // Resolve program ID with consistent precedence
107
153
  const programId = ProgramIdResolver.resolve(fiveVMProgramId || options.fiveVMProgramId);
108
154
  const exportMetadata = encodeExportMetadata(options.exportMetadata);
@@ -110,7 +156,7 @@ export async function generateDeployInstruction(bytecode, deployer, options = {}
110
156
  console.log(`[FiveSDK] Generating deployment transaction (${bytecode.length} bytes)...`);
111
157
  console.log(`[FiveSDK] Using program ID: ${programId}`);
112
158
  }
113
- const scriptResult = await PDAUtils.deriveScriptAccount(bytecode, programId);
159
+ const scriptResult = await resolveScriptAccountDerivation(bytecode, deployer, programId, options);
114
160
  const scriptAccount = scriptResult.address;
115
161
  const scriptSeed = scriptResult.seed;
116
162
  const vmStatePDAResult = await PDAUtils.deriveVMStatePDA(programId);
@@ -119,9 +165,8 @@ export async function generateDeployInstruction(bytecode, deployer, options = {}
119
165
  console.log(`[FiveSDK] Script Account: ${scriptAccount} (seed: ${scriptSeed})`);
120
166
  console.log(`[FiveSDK] VM State PDA: ${vmStatePDA}`);
121
167
  }
122
- const SCRIPT_HEADER_SIZE = 64; // ScriptAccountHeader size from Rust program
123
- const totalAccountSize = SCRIPT_HEADER_SIZE + exportMetadata.length + bytecode.length;
124
- const rentLamports = await RentCalculator.calculateRentExemption(totalAccountSize);
168
+ const totalAccountSize = SCRIPT_ACCOUNT_HEADER_LEN + exportMetadata.length + bytecode.length;
169
+ const rentLamports = await RentCalculator.calculateRentExemptionWithConnection(totalAccountSize, connection);
125
170
  const { deployFeeLamports } = await readVMStateFeeConfig(connection, vmStatePDA);
126
171
  const deployShardIndex = 0;
127
172
  const deployVault = await deriveProgramFeeVault(programId, deployShardIndex);
@@ -196,9 +241,8 @@ options = {}) {
196
241
  const scriptKeypair = Keypair.generate();
197
242
  const scriptAccount = scriptKeypair.publicKey.toString();
198
243
  // Calculate account size and rent
199
- const SCRIPT_HEADER_SIZE = 64; // ScriptHeader::LEN
200
244
  const exportMetadata = encodeExportMetadata(options.exportMetadata);
201
- const totalAccountSize = SCRIPT_HEADER_SIZE + exportMetadata.length + bytecode.length;
245
+ const totalAccountSize = SCRIPT_ACCOUNT_HEADER_LEN + exportMetadata.length + bytecode.length;
202
246
  const rentLamports = await connection.getMinimumBalanceForRentExemption(totalAccountSize);
203
247
  const vmStatePDA = await PDAUtils.deriveVMStatePDA(programIdStr);
204
248
  const vmStatePubkey = new PublicKey(vmStatePDA.address);
@@ -216,7 +260,8 @@ options = {}) {
216
260
  }));
217
261
  }
218
262
  // 1. Initialize canonical VM State if missing
219
- const vmStateInfo = await connection.getAccountInfo(vmStatePubkey, "finalized");
263
+ const bootstrapCommitment = selectBootstrapCommitment(connection);
264
+ const vmStateInfo = await connection.getAccountInfo(vmStatePubkey, bootstrapCommitment);
220
265
  if (!vmStateInfo) {
221
266
  tx.add(new TransactionInstruction({
222
267
  keys: [
@@ -280,17 +325,18 @@ options = {}) {
280
325
  console.log(`[FiveSDK] Generated script keypair: ${scriptAccount}`);
281
326
  }
282
327
  // Calculate account size and rent
283
- const SCRIPT_HEADER_SIZE = 64; // ScriptHeader::LEN (five-protocol)
284
328
  const exportMetadata = encodeExportMetadata(options.exportMetadata);
285
- const totalAccountSize = SCRIPT_HEADER_SIZE + exportMetadata.length + bytecode.length;
329
+ const totalAccountSize = SCRIPT_ACCOUNT_HEADER_LEN + exportMetadata.length + bytecode.length;
286
330
  const rentLamports = await connection.getMinimumBalanceForRentExemption(totalAccountSize);
287
331
  const vmStateResolution = await ensureCanonicalVmStateAccount(connection, deployerKeypair, new PublicKey(programId), {
288
332
  vmStateAccount: options.vmStateAccount,
289
333
  maxRetries: options.maxRetries,
290
334
  debug: options.debug,
335
+ network: options.network,
291
336
  });
292
337
  const vmStatePubkey = vmStateResolution.vmStatePubkey;
293
338
  const vmStateRent = vmStateResolution.vmStateRent;
339
+ const bootstrapCommitment = selectBootstrapCommitment(connection, options.network);
294
340
  const vmStateFeeConfig = await readVMStateFeeConfig(connection, vmStatePubkey.toString());
295
341
  const deployShardIndex = 0;
296
342
  const deployVault = await deriveProgramFeeVault(programId, deployShardIndex);
@@ -313,7 +359,7 @@ options = {}) {
313
359
  console.log(`[FiveSDK] Export metadata size: ${exportMetadata.length} bytes`);
314
360
  console.log(`[FiveSDK] Rent cost: ${((rentLamports + vmStateRent) / 1e9)} SOL`);
315
361
  }
316
- const feeVaultInitSigs = await initProgramFeeVaultShards(connection, programId, vmStatePubkey.toString(), vmStateFeeConfig.shardCount, deployerKeypair, { debug: options.debug, maxRetries: options.maxRetries });
362
+ const feeVaultInitSigs = await initProgramFeeVaultShards(connection, programId, vmStatePubkey.toString(), vmStateFeeConfig.shardCount, deployerKeypair, { debug: options.debug, maxRetries: options.maxRetries, network: options.network });
317
363
  // SINGLE TRANSACTION: create script account + deploy bytecode
318
364
  const tx = new Transaction();
319
365
  // Optional compute budget
@@ -378,19 +424,20 @@ options = {}) {
378
424
  if (options.debug) {
379
425
  console.log(`[FiveSDK] Transaction serialized: ${txSerialized.length} bytes`);
380
426
  }
381
- const signature = await connection.sendRawTransaction(txSerialized, {
382
- skipPreflight: true,
383
- preflightCommitment: "confirmed",
427
+ const sendResult = await sendAndConfirmRawTransactionRobust(connection, txSerialized, {
428
+ commitment: "confirmed",
429
+ timeoutMs: 120000,
430
+ debug: options.debug,
384
431
  maxRetries: options.maxRetries || 3,
432
+ skipPreflight: false,
433
+ preflightCommitment: "confirmed",
385
434
  });
435
+ const signature = sendResult.signature;
386
436
  if (options.debug) {
387
437
  console.log(`[FiveSDK] sendRawTransaction completed, returned signature: ${signature}`);
388
438
  }
389
- // Custom confirmation polling with extended timeout (120 seconds)
390
- const confirmationResult = await pollForConfirmation(connection, signature, "confirmed", 120000, // 120 second timeout
391
- options.debug);
392
- if (!confirmationResult.success) {
393
- const errorMessage = `Deployment confirmation failed: ${confirmationResult.error || "Unknown error"}`;
439
+ if (!sendResult.success || !signature) {
440
+ const errorMessage = `Deployment confirmation failed: ${sendResult.error || "Unknown error"}`;
394
441
  if (options.debug)
395
442
  console.log(`[FiveSDK] ${errorMessage}`);
396
443
  return {
@@ -399,8 +446,8 @@ options = {}) {
399
446
  transactionId: signature,
400
447
  };
401
448
  }
402
- if (confirmationResult.err) {
403
- const errorMessage = `Combined deployment failed: ${JSON.stringify(confirmationResult.err)}`;
449
+ if (sendResult.err) {
450
+ const errorMessage = `Combined deployment failed: ${JSON.stringify(sendResult.err)}`;
404
451
  if (options.debug)
405
452
  console.log(`[FiveSDK] ${errorMessage}`);
406
453
  return {
@@ -468,8 +515,7 @@ options = {}) {
468
515
  const scriptKeypair = Keypair.generate();
469
516
  const scriptAccount = scriptKeypair.publicKey.toString();
470
517
  // Calculate account size and rent
471
- const SCRIPT_HEADER_SIZE = 64; // ScriptHeader::LEN (five-protocol)
472
- const totalAccountSize = SCRIPT_HEADER_SIZE + bytecode.length;
518
+ const totalAccountSize = SCRIPT_ACCOUNT_HEADER_LEN + bytecode.length;
473
519
  const rentLamports = await connection.getMinimumBalanceForRentExemption(totalAccountSize);
474
520
  const programIdStr = ProgramIdResolver.resolve(options.fiveVMProgramId);
475
521
  const programId = new PublicKey(programIdStr);
@@ -477,9 +523,11 @@ options = {}) {
477
523
  vmStateAccount: options.vmStateAccount,
478
524
  maxRetries: options.maxRetries,
479
525
  debug: options.debug,
526
+ network: options.network,
480
527
  });
481
528
  const vmStatePubkey = vmStateResolution.vmStatePubkey;
482
529
  const vmStateRent = vmStateResolution.vmStateRent;
530
+ const bootstrapCommitment = selectBootstrapCommitment(connection, options.network);
483
531
  const vmStateFeeConfig = await readVMStateFeeConfig(connection, vmStatePubkey.toString());
484
532
  const deployShardIndex = 0;
485
533
  const deployVault = await deriveProgramFeeVault(programIdStr, deployShardIndex);
@@ -501,7 +549,7 @@ options = {}) {
501
549
  console.log(`[FiveSDK] Total account size: ${totalAccountSize} bytes`);
502
550
  console.log(`[FiveSDK] Initial rent cost: ${(rentLamports + vmStateRent) / 1e9} SOL`);
503
551
  }
504
- const feeVaultInitSigs = await initProgramFeeVaultShards(connection, programIdStr, vmStatePubkey.toString(), vmStateFeeConfig.shardCount, deployerKeypair, { debug: options.debug, maxRetries: options.maxRetries });
552
+ const feeVaultInitSigs = await initProgramFeeVaultShards(connection, programIdStr, vmStatePubkey.toString(), vmStateFeeConfig.shardCount, deployerKeypair, { debug: options.debug, maxRetries: options.maxRetries, network: options.network });
505
553
  const transactionIds = [];
506
554
  let totalCost = rentLamports + vmStateRent;
507
555
  // TRANSACTION 1: Create Account + InitLargeProgram
@@ -514,7 +562,7 @@ options = {}) {
514
562
  fromPubkey: deployerKeypair.publicKey,
515
563
  newAccountPubkey: scriptKeypair.publicKey,
516
564
  lamports: rentLamports,
517
- space: SCRIPT_HEADER_SIZE, // Start with just header space
565
+ space: SCRIPT_ACCOUNT_HEADER_LEN, // Start with just the ScriptAccountHeader
518
566
  programId: programId,
519
567
  });
520
568
  initTransaction.add(createAccountInstruction);
@@ -535,7 +583,7 @@ options = {}) {
535
583
  {
536
584
  pubkey: vmStatePubkey,
537
585
  isSigner: false,
538
- isWritable: false,
586
+ isWritable: true,
539
587
  },
540
588
  ...feeVaultKeys,
541
589
  ],
@@ -545,23 +593,24 @@ options = {}) {
545
593
  initTransaction.add(initLargeProgramInstruction);
546
594
  // Sign and send initialization transaction
547
595
  initTransaction.feePayer = deployerKeypair.publicKey;
548
- const { blockhash } = await connection.getLatestBlockhash("confirmed");
549
- initTransaction.recentBlockhash = blockhash;
596
+ const initBlockhash = await connection.getLatestBlockhash("confirmed");
597
+ initTransaction.recentBlockhash = initBlockhash.blockhash;
550
598
  initTransaction.partialSign(deployerKeypair);
551
599
  initTransaction.partialSign(scriptKeypair);
552
- const initSignature = await connection.sendRawTransaction(initTransaction.serialize(), {
553
- skipPreflight: true,
554
- preflightCommitment: "confirmed",
555
- maxRetries: options.maxRetries || 3,
556
- });
557
- const initConfirm = await confirmTransactionRobust(connection, initSignature, {
558
- commitment: "finalized",
600
+ const initSend = await sendAndConfirmRawTransactionRobust(connection, initTransaction.serialize(), {
601
+ commitment: bootstrapCommitment,
559
602
  timeoutMs: 120000,
560
603
  debug: options.debug,
604
+ maxRetries: options.maxRetries || 3,
605
+ skipPreflight: false,
606
+ preflightCommitment: "confirmed",
607
+ blockhash: initBlockhash.blockhash,
608
+ lastValidBlockHeight: initBlockhash.lastValidBlockHeight,
561
609
  });
562
- if (!initConfirm.success) {
563
- throw new Error(`Initialization confirmation failed: ${initConfirm.error || "unconfirmed"}`);
610
+ if (!initSend.success || !initSend.signature) {
611
+ throw new Error(`Initialization confirmation failed: ${initSend.error || "unconfirmed"}`);
564
612
  }
613
+ const initSignature = initSend.signature;
565
614
  transactionIds.push(initSignature);
566
615
  if (options.debug) {
567
616
  console.log(`[FiveSDK] ✅ Initialization completed: ${initSignature}`);
@@ -580,7 +629,7 @@ options = {}) {
580
629
  console.log(`[FiveSDK] Step ${i + 2}: Appending chunk ${i + 1}/${chunks.length} (${chunk.length} bytes)`);
581
630
  }
582
631
  // Calculate additional rent needed for this chunk
583
- const currentInfo = await getAccountInfoWithRetry(connection, scriptKeypair.publicKey, { commitment: "finalized", retries: 2, delayMs: 1000, debug: options.debug });
632
+ const currentInfo = await getAccountInfoWithRetry(connection, scriptKeypair.publicKey, { commitment: bootstrapCommitment, retries: 2, delayMs: 1000, debug: options.debug });
584
633
  if (!currentInfo)
585
634
  throw new Error("Script account not found after initialization");
586
635
  const newSize = currentInfo.data.length + chunk.length;
@@ -633,7 +682,7 @@ options = {}) {
633
682
  {
634
683
  pubkey: vmStatePubkey,
635
684
  isSigner: false,
636
- isWritable: false,
685
+ isWritable: true,
637
686
  },
638
687
  ...feeVaultKeys,
639
688
  ],
@@ -646,19 +695,20 @@ options = {}) {
646
695
  appendTransaction.feePayer = deployerKeypair.publicKey;
647
696
  appendTransaction.recentBlockhash = appendBlockhash.blockhash;
648
697
  appendTransaction.partialSign(deployerKeypair);
649
- const appendSignature = await connection.sendRawTransaction(appendTransaction.serialize(), {
650
- skipPreflight: true,
651
- preflightCommitment: "confirmed",
652
- maxRetries: options.maxRetries || 3,
653
- });
654
- const appendConfirm = await confirmTransactionRobust(connection, appendSignature, {
655
- commitment: "finalized",
698
+ const appendSend = await sendAndConfirmRawTransactionRobust(connection, appendTransaction.serialize(), {
699
+ commitment: bootstrapCommitment,
656
700
  timeoutMs: 120000,
657
701
  debug: options.debug,
702
+ maxRetries: options.maxRetries || 3,
703
+ skipPreflight: false,
704
+ preflightCommitment: "confirmed",
705
+ blockhash: appendBlockhash.blockhash,
706
+ lastValidBlockHeight: appendBlockhash.lastValidBlockHeight,
658
707
  });
659
- if (!appendConfirm.success) {
660
- throw new Error(`Append confirmation failed: ${appendConfirm.error || "unconfirmed"}`);
708
+ if (!appendSend.success || !appendSend.signature) {
709
+ throw new Error(`Append confirmation failed: ${appendSend.error || "unconfirmed"}`);
661
710
  }
711
+ const appendSignature = appendSend.signature;
662
712
  transactionIds.push(appendSignature);
663
713
  if (options.debug) {
664
714
  console.log(`[FiveSDK] ✅ Chunk ${i + 1} appended: ${appendSignature}`);
@@ -666,7 +716,7 @@ options = {}) {
666
716
  }
667
717
  // Final verification
668
718
  let finalInfo = await getAccountInfoWithRetry(connection, scriptKeypair.publicKey, {
669
- commitment: "finalized",
719
+ commitment: bootstrapCommitment,
670
720
  retries: 2,
671
721
  delayMs: 1000,
672
722
  debug: options.debug,
@@ -674,7 +724,7 @@ options = {}) {
674
724
  if (!finalInfo) {
675
725
  throw new Error("Script account not found during final verification");
676
726
  }
677
- const expectedSize = SCRIPT_HEADER_SIZE + bytecode.length;
727
+ const expectedSize = SCRIPT_ACCOUNT_HEADER_LEN + bytecode.length;
678
728
  if (options.debug) {
679
729
  console.log(`[FiveSDK] 🔍 Final verification:`);
680
730
  console.log(`[FiveSDK] Expected size: ${expectedSize} bytes`);
@@ -738,8 +788,7 @@ options = {}) {
738
788
  const scriptKeypair = Keypair.generate();
739
789
  const scriptAccount = scriptKeypair.publicKey.toString();
740
790
  // Calculate full account size upfront
741
- const SCRIPT_HEADER_SIZE = 64; // ScriptAccountHeader::LEN
742
- const totalAccountSize = SCRIPT_HEADER_SIZE + bytecode.length;
791
+ const totalAccountSize = SCRIPT_ACCOUNT_HEADER_LEN + bytecode.length;
743
792
  const rentLamports = await connection.getMinimumBalanceForRentExemption(totalAccountSize);
744
793
  const programIdStr = ProgramIdResolver.resolve(options.fiveVMProgramId);
745
794
  const programId = new PublicKey(programIdStr);
@@ -747,9 +796,11 @@ options = {}) {
747
796
  vmStateAccount: options.vmStateAccount,
748
797
  maxRetries: options.maxRetries,
749
798
  debug: options.debug,
799
+ network: options.network,
750
800
  });
751
801
  const vmStatePubkey = vmStateResolution.vmStatePubkey;
752
802
  const vmStateRent = vmStateResolution.vmStateRent;
803
+ const bootstrapCommitment = selectBootstrapCommitment(connection, options.network);
753
804
  const vmStateFeeConfig = await readVMStateFeeConfig(connection, vmStatePubkey.toString());
754
805
  const deployShardIndex = 0;
755
806
  const deployVault = await deriveProgramFeeVault(programIdStr, deployShardIndex);
@@ -771,7 +822,7 @@ options = {}) {
771
822
  console.log(`[FiveSDK] PRE-ALLOCATED full account size: ${totalAccountSize} bytes`);
772
823
  console.log(`[FiveSDK] Full rent cost paid upfront: ${(rentLamports + vmStateRent) / 1e9} SOL`);
773
824
  }
774
- const feeVaultInitSigs = await initProgramFeeVaultShards(connection, programIdStr, vmStatePubkey.toString(), vmStateFeeConfig.shardCount, deployerKeypair, { debug: options.debug, maxRetries: options.maxRetries });
825
+ const feeVaultInitSigs = await initProgramFeeVaultShards(connection, programIdStr, vmStatePubkey.toString(), vmStateFeeConfig.shardCount, deployerKeypair, { debug: options.debug, maxRetries: options.maxRetries, network: options.network });
775
826
  const transactionIds = [];
776
827
  let totalCost = rentLamports + vmStateRent;
777
828
  const chunks = chunkBytecode(bytecode, chunkSize);
@@ -808,7 +859,7 @@ options = {}) {
808
859
  {
809
860
  pubkey: vmStatePubkey,
810
861
  isSigner: false,
811
- isWritable: false,
862
+ isWritable: true,
812
863
  },
813
864
  ...feeVaultKeys,
814
865
  ],
@@ -821,19 +872,24 @@ options = {}) {
821
872
  initTransaction.recentBlockhash = blockhash;
822
873
  initTransaction.partialSign(deployerKeypair);
823
874
  initTransaction.partialSign(scriptKeypair);
824
- const initSignature = await connection.sendRawTransaction(initTransaction.serialize(), {
825
- skipPreflight: true,
826
- preflightCommitment: "confirmed",
875
+ const initSend = await sendAndConfirmRawTransactionRobust(connection, initTransaction.serialize(), {
876
+ commitment: "confirmed",
877
+ timeoutMs: 120000,
878
+ debug: options.debug,
827
879
  maxRetries: options.maxRetries || 3,
880
+ skipPreflight: false,
881
+ preflightCommitment: "confirmed",
882
+ blockhash: blockhash,
883
+ lastValidBlockHeight: undefined,
828
884
  });
829
- const initConfirmation = await pollForConfirmation(connection, initSignature, "confirmed", 120000, options.debug);
830
- if (!initConfirmation.success) {
885
+ if (!initSend.success || !initSend.signature) {
831
886
  return {
832
887
  success: false,
833
- error: `Initialization confirmation failed: ${initConfirmation.error}`,
888
+ error: `Initialization confirmation failed: ${initSend.error}`,
834
889
  transactionIds
835
890
  };
836
891
  }
892
+ const initSignature = initSend.signature;
837
893
  transactionIds.push(initSignature);
838
894
  if (options.debug) {
839
895
  console.log(`[FiveSDK] ✅ Optimized initialization completed: ${initSignature}`);
@@ -916,19 +972,24 @@ options = {}) {
916
972
  appendTransaction.feePayer = deployerKeypair.publicKey;
917
973
  appendTransaction.recentBlockhash = appendBlockhash.blockhash;
918
974
  appendTransaction.partialSign(deployerKeypair);
919
- const appendSignature = await connection.sendRawTransaction(appendTransaction.serialize(), {
920
- skipPreflight: true,
921
- preflightCommitment: "confirmed",
975
+ const appendSend = await sendAndConfirmRawTransactionRobust(connection, appendTransaction.serialize(), {
976
+ commitment: bootstrapCommitment,
977
+ timeoutMs: 120000,
978
+ debug: options.debug,
922
979
  maxRetries: options.maxRetries || 3,
980
+ skipPreflight: false,
981
+ preflightCommitment: "confirmed",
982
+ blockhash: appendBlockhash.blockhash,
983
+ lastValidBlockHeight: appendBlockhash.lastValidBlockHeight,
923
984
  });
924
- const appendConfirmation = await pollForConfirmation(connection, appendSignature, "finalized", 120000, options.debug);
925
- if (!appendConfirmation.success) {
985
+ if (!appendSend.success || !appendSend.signature) {
926
986
  return {
927
987
  success: false,
928
- error: `Append confirmation failed: ${appendConfirmation.error}`,
988
+ error: `Append confirmation failed: ${appendSend.error}`,
929
989
  transactionIds
930
990
  };
931
991
  }
992
+ const appendSignature = appendSend.signature;
932
993
  transactionIds.push(appendSignature);
933
994
  if (options.debug) {
934
995
  console.log(`[FiveSDK] ✅ Multi-chunk append completed: ${appendSignature}`);
@@ -962,17 +1023,20 @@ options = {}) {
962
1023
  const finalizeBlockhash = await connection.getLatestBlockhash("confirmed");
963
1024
  finalizeTransaction.recentBlockhash = finalizeBlockhash.blockhash;
964
1025
  finalizeTransaction.partialSign(deployerKeypair);
965
- const finalizeSignature = await connection.sendRawTransaction(finalizeTransaction.serialize(), {
966
- skipPreflight: true,
967
- preflightCommitment: "confirmed",
1026
+ const finalizeSend = await sendAndConfirmRawTransactionRobust(connection, finalizeTransaction.serialize(), {
1027
+ commitment: bootstrapCommitment,
1028
+ timeoutMs: 120000,
1029
+ debug: options.debug,
968
1030
  maxRetries: options.maxRetries || 3,
1031
+ skipPreflight: false,
1032
+ preflightCommitment: "confirmed",
1033
+ blockhash: finalizeBlockhash.blockhash,
1034
+ lastValidBlockHeight: finalizeBlockhash.lastValidBlockHeight,
969
1035
  });
970
- // Use custom polling for finalize to handle validator latency
971
- const finalizeConfirmation = await pollForConfirmation(connection, finalizeSignature, "finalized", 120000, // 120 second timeout
972
- options.debug);
973
- if (!finalizeConfirmation.success) {
974
- console.error(`[FiveSDK] FinalizeScript confirmation failed: ${finalizeConfirmation.error}`);
1036
+ if (!finalizeSend.success || !finalizeSend.signature) {
1037
+ console.error(`[FiveSDK] FinalizeScript confirmation failed: ${finalizeSend.error}`);
975
1038
  }
1039
+ const finalizeSignature = finalizeSend.signature;
976
1040
  transactionIds.push(finalizeSignature);
977
1041
  if (options.debug) {
978
1042
  console.log(`[FiveSDK] ✅ FinalizeScript completed: ${finalizeSignature}`);
@@ -1095,7 +1159,8 @@ async function ensureCanonicalVmStateAccount(connection, deployerKeypair, progra
1095
1159
  throw new Error(`vmStateAccount must be canonical PDA ${canonical.address}; got ${options.vmStateAccount}`);
1096
1160
  }
1097
1161
  const vmStatePubkey = new PublicKey(canonical.address);
1098
- const existing = await connection.getAccountInfo(vmStatePubkey, "finalized");
1162
+ const bootstrapCommitment = selectBootstrapCommitment(connection, options.network);
1163
+ const existing = await connection.getAccountInfo(vmStatePubkey, bootstrapCommitment);
1099
1164
  if (existing) {
1100
1165
  if (existing.owner.toBase58() !== programId.toBase58()) {
1101
1166
  throw new Error(`canonical VM state ${canonical.address} exists but is owned by ${existing.owner.toBase58()}, expected ${programId.toBase58()}`);
@@ -1125,14 +1190,18 @@ async function ensureCanonicalVmStateAccount(connection, deployerKeypair, progra
1125
1190
  const initBlockhash = await connection.getLatestBlockhash("confirmed");
1126
1191
  initTransaction.recentBlockhash = initBlockhash.blockhash;
1127
1192
  initTransaction.partialSign(deployerKeypair);
1128
- const initSignature = await connection.sendRawTransaction(initTransaction.serialize(), {
1129
- skipPreflight: true,
1130
- preflightCommitment: "confirmed",
1193
+ const initSend = await sendAndConfirmRawTransactionRobust(connection, initTransaction.serialize(), {
1194
+ commitment: "confirmed",
1195
+ timeoutMs: 120000,
1196
+ debug: options.debug,
1131
1197
  maxRetries: options.maxRetries || 3,
1198
+ skipPreflight: false,
1199
+ preflightCommitment: "confirmed",
1200
+ blockhash: initBlockhash.blockhash,
1201
+ lastValidBlockHeight: initBlockhash.lastValidBlockHeight,
1132
1202
  });
1133
- const initConfirmation = await pollForConfirmation(connection, initSignature, "confirmed", 120000, options.debug);
1134
- if (!initConfirmation.success || initConfirmation.err) {
1135
- throw new Error(`canonical VM state initialization failed: ${initConfirmation.error || JSON.stringify(initConfirmation.err)}`);
1203
+ if (!initSend.success || initSend.err) {
1204
+ throw new Error(`canonical VM state initialization failed: ${initSend.error || JSON.stringify(initSend.err)}`);
1136
1205
  }
1137
1206
  return { vmStatePubkey, vmStateRent, created: true, bump: canonical.bump };
1138
1207
  }
@@ -65,6 +65,11 @@ export declare function executeOnSolana(scriptAccount: string, connection: any,
65
65
  vmStateAccount?: string;
66
66
  fiveVMProgramId?: string;
67
67
  abi?: any;
68
+ accountMetadata?: Map<string, {
69
+ isSigner: boolean;
70
+ isWritable: boolean;
71
+ isSystemAccount?: boolean;
72
+ }>;
68
73
  feeShardIndex?: number;
69
74
  payerAccount?: string;
70
75
  }): Promise<{