@5ive-tech/sdk 1.1.10 → 1.1.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/FiveSDK.d.ts +1 -4
- package/dist/FiveSDK.js +47 -5
- package/dist/accounts/index.js +3 -2
- package/dist/assets/vm/dummy.file +0 -0
- package/dist/assets/vm/five_vm_wasm_bg.js +3307 -0
- package/dist/assets/vm/five_vm_wasm_bg.wasm +0 -0
- package/dist/assets/vm/five_vm_wasm_bg.wasm.d.ts +5 -5
- package/dist/compiler/BytecodeCompiler.d.ts +1 -7
- package/dist/compiler/BytecodeCompiler.js +105 -44
- package/dist/config/ProgramIdResolver.d.ts +1 -6
- package/dist/config/ProgramIdResolver.js +11 -16
- package/dist/config/VmClusterConfigResolver.d.ts +27 -0
- package/dist/config/VmClusterConfigResolver.js +111 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/modules/accounts.js +7 -1
- package/dist/modules/admin.js +25 -12
- package/dist/modules/deploy.js +55 -21
- package/dist/modules/execute.js +58 -32
- package/dist/modules/vm-state.js +6 -1
- package/dist/project/config.js +0 -1
- package/dist/testing/TestRunner.js +6 -1
- package/dist/types.d.ts +19 -2
- package/dist/utils/abi.d.ts +4 -0
- package/dist/utils/abi.js +3 -0
- package/dist/utils/transaction.d.ts +22 -0
- package/dist/utils/transaction.js +94 -12
- package/dist/wasm/compiler/CompilationLogic.d.ts +0 -5
- package/dist/wasm/compiler/CompilationLogic.js +45 -163
- package/dist/wasm/compiler/FiveCompiler.d.ts +0 -5
- package/dist/wasm/compiler/FiveCompiler.js +0 -6
- package/dist/wasm/compiler/utils.d.ts +34 -1
- package/dist/wasm/compiler/utils.js +223 -5
- package/package.json +4 -3
package/dist/modules/deploy.js
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
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 { pollForConfirmation } from "../utils/transaction.js";
|
|
4
|
+
import { confirmTransactionRobust, getAccountInfoWithRetry, pollForConfirmation, SDK_COMMITMENTS, } from "../utils/transaction.js";
|
|
5
5
|
import { ProgramIdResolver } from "../config/ProgramIdResolver.js";
|
|
6
|
-
|
|
6
|
+
import { VmClusterConfigResolver } from "../config/VmClusterConfigResolver.js";
|
|
7
|
+
const DEFAULT_FEE_VAULT_SHARD_COUNT = (() => {
|
|
8
|
+
try {
|
|
9
|
+
return VmClusterConfigResolver.loadClusterConfig().feeVaultShardCount;
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return 2;
|
|
13
|
+
}
|
|
14
|
+
})();
|
|
7
15
|
const FEE_VAULT_NAMESPACE_SEED = Buffer.from([
|
|
8
16
|
0xff, 0x66, 0x69, 0x76, 0x65, 0x5f, 0x76, 0x6d, 0x5f, 0x66, 0x65, 0x65,
|
|
9
17
|
0x5f, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x76, 0x31,
|
|
@@ -14,7 +22,11 @@ async function readVMStateFeeConfig(connection, vmStateAddress) {
|
|
|
14
22
|
}
|
|
15
23
|
try {
|
|
16
24
|
const { PublicKey } = await import("@solana/web3.js");
|
|
17
|
-
const info = await connection
|
|
25
|
+
const info = await getAccountInfoWithRetry(connection, new PublicKey(vmStateAddress), {
|
|
26
|
+
commitment: SDK_COMMITMENTS.READ,
|
|
27
|
+
retries: 2,
|
|
28
|
+
delayMs: 700,
|
|
29
|
+
});
|
|
18
30
|
if (!info) {
|
|
19
31
|
return { shardCount: DEFAULT_FEE_VAULT_SHARD_COUNT };
|
|
20
32
|
}
|
|
@@ -64,7 +76,14 @@ async function initProgramFeeVaultShards(connection, programId, vmStateAccount,
|
|
|
64
76
|
preflightCommitment: "confirmed",
|
|
65
77
|
maxRetries: options.maxRetries || 3,
|
|
66
78
|
});
|
|
67
|
-
await connection
|
|
79
|
+
const shardConfirm = await confirmTransactionRobust(connection, sig, {
|
|
80
|
+
commitment: "finalized",
|
|
81
|
+
timeoutMs: 120000,
|
|
82
|
+
debug: options.debug,
|
|
83
|
+
});
|
|
84
|
+
if (!shardConfirm.success) {
|
|
85
|
+
throw new Error(`Fee vault shard init failed: ${shardConfirm.error || "unconfirmed"}`);
|
|
86
|
+
}
|
|
68
87
|
signatures.push(sig);
|
|
69
88
|
if (options.debug) {
|
|
70
89
|
console.log(`[FiveSDK] Initialized fee vault shard ${shardIndex}: ${vault.address}`);
|
|
@@ -192,7 +211,7 @@ options = {}) {
|
|
|
192
211
|
}));
|
|
193
212
|
}
|
|
194
213
|
// 1. Initialize canonical VM State if missing
|
|
195
|
-
const vmStateInfo = await connection.getAccountInfo(vmStatePubkey);
|
|
214
|
+
const vmStateInfo = await connection.getAccountInfo(vmStatePubkey, "finalized");
|
|
196
215
|
if (!vmStateInfo) {
|
|
197
216
|
tx.add(new TransactionInstruction({
|
|
198
217
|
keys: [
|
|
@@ -530,7 +549,14 @@ options = {}) {
|
|
|
530
549
|
preflightCommitment: "confirmed",
|
|
531
550
|
maxRetries: options.maxRetries || 3,
|
|
532
551
|
});
|
|
533
|
-
await connection
|
|
552
|
+
const initConfirm = await confirmTransactionRobust(connection, initSignature, {
|
|
553
|
+
commitment: "finalized",
|
|
554
|
+
timeoutMs: 120000,
|
|
555
|
+
debug: options.debug,
|
|
556
|
+
});
|
|
557
|
+
if (!initConfirm.success) {
|
|
558
|
+
throw new Error(`Initialization confirmation failed: ${initConfirm.error || "unconfirmed"}`);
|
|
559
|
+
}
|
|
534
560
|
transactionIds.push(initSignature);
|
|
535
561
|
if (options.debug) {
|
|
536
562
|
console.log(`[FiveSDK] ✅ Initialization completed: ${initSignature}`);
|
|
@@ -549,16 +575,9 @@ options = {}) {
|
|
|
549
575
|
console.log(`[FiveSDK] Step ${i + 2}: Appending chunk ${i + 1}/${chunks.length} (${chunk.length} bytes)`);
|
|
550
576
|
}
|
|
551
577
|
// Calculate additional rent needed for this chunk
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
if (options.debug)
|
|
556
|
-
console.log(`[FiveSDK] Account info null, retrying...`);
|
|
557
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
558
|
-
currentInfo = await connection.getAccountInfo(scriptKeypair.publicKey);
|
|
559
|
-
if (!currentInfo)
|
|
560
|
-
throw new Error("Script account not found after initialization");
|
|
561
|
-
}
|
|
578
|
+
const currentInfo = await getAccountInfoWithRetry(connection, scriptKeypair.publicKey, { commitment: "finalized", retries: 2, delayMs: 1000, debug: options.debug });
|
|
579
|
+
if (!currentInfo)
|
|
580
|
+
throw new Error("Script account not found after initialization");
|
|
562
581
|
const newSize = currentInfo.data.length + chunk.length;
|
|
563
582
|
const newRentRequired = await connection.getMinimumBalanceForRentExemption(newSize);
|
|
564
583
|
const additionalRent = Math.max(0, newRentRequired - currentInfo.lamports);
|
|
@@ -627,14 +646,29 @@ options = {}) {
|
|
|
627
646
|
preflightCommitment: "confirmed",
|
|
628
647
|
maxRetries: options.maxRetries || 3,
|
|
629
648
|
});
|
|
630
|
-
await connection
|
|
649
|
+
const appendConfirm = await confirmTransactionRobust(connection, appendSignature, {
|
|
650
|
+
commitment: "finalized",
|
|
651
|
+
timeoutMs: 120000,
|
|
652
|
+
debug: options.debug,
|
|
653
|
+
});
|
|
654
|
+
if (!appendConfirm.success) {
|
|
655
|
+
throw new Error(`Append confirmation failed: ${appendConfirm.error || "unconfirmed"}`);
|
|
656
|
+
}
|
|
631
657
|
transactionIds.push(appendSignature);
|
|
632
658
|
if (options.debug) {
|
|
633
659
|
console.log(`[FiveSDK] ✅ Chunk ${i + 1} appended: ${appendSignature}`);
|
|
634
660
|
}
|
|
635
661
|
}
|
|
636
662
|
// Final verification
|
|
637
|
-
|
|
663
|
+
let finalInfo = await getAccountInfoWithRetry(connection, scriptKeypair.publicKey, {
|
|
664
|
+
commitment: "finalized",
|
|
665
|
+
retries: 2,
|
|
666
|
+
delayMs: 1000,
|
|
667
|
+
debug: options.debug,
|
|
668
|
+
});
|
|
669
|
+
if (!finalInfo) {
|
|
670
|
+
throw new Error("Script account not found during final verification");
|
|
671
|
+
}
|
|
638
672
|
const expectedSize = SCRIPT_HEADER_SIZE + bytecode.length;
|
|
639
673
|
if (options.debug) {
|
|
640
674
|
console.log(`[FiveSDK] 🔍 Final verification:`);
|
|
@@ -882,7 +916,7 @@ options = {}) {
|
|
|
882
916
|
preflightCommitment: "confirmed",
|
|
883
917
|
maxRetries: options.maxRetries || 3,
|
|
884
918
|
});
|
|
885
|
-
const appendConfirmation = await pollForConfirmation(connection, appendSignature, "
|
|
919
|
+
const appendConfirmation = await pollForConfirmation(connection, appendSignature, "finalized", 120000, options.debug);
|
|
886
920
|
if (!appendConfirmation.success) {
|
|
887
921
|
return {
|
|
888
922
|
success: false,
|
|
@@ -929,7 +963,7 @@ options = {}) {
|
|
|
929
963
|
maxRetries: options.maxRetries || 3,
|
|
930
964
|
});
|
|
931
965
|
// Use custom polling for finalize to handle validator latency
|
|
932
|
-
const finalizeConfirmation = await pollForConfirmation(connection, finalizeSignature, "
|
|
966
|
+
const finalizeConfirmation = await pollForConfirmation(connection, finalizeSignature, "finalized", 120000, // 120 second timeout
|
|
933
967
|
options.debug);
|
|
934
968
|
if (!finalizeConfirmation.success) {
|
|
935
969
|
console.error(`[FiveSDK] FinalizeScript confirmation failed: ${finalizeConfirmation.error}`);
|
|
@@ -1056,7 +1090,7 @@ async function ensureCanonicalVmStateAccount(connection, deployerKeypair, progra
|
|
|
1056
1090
|
throw new Error(`vmStateAccount must be canonical PDA ${canonical.address}; got ${options.vmStateAccount}`);
|
|
1057
1091
|
}
|
|
1058
1092
|
const vmStatePubkey = new PublicKey(canonical.address);
|
|
1059
|
-
const existing = await connection.getAccountInfo(vmStatePubkey);
|
|
1093
|
+
const existing = await connection.getAccountInfo(vmStatePubkey, "finalized");
|
|
1060
1094
|
if (existing) {
|
|
1061
1095
|
if (existing.owner.toBase58() !== programId.toBase58()) {
|
|
1062
1096
|
throw new Error(`canonical VM state ${canonical.address} exists but is owned by ${existing.owner.toBase58()}, expected ${programId.toBase58()}`);
|
package/dist/modules/execute.js
CHANGED
|
@@ -7,7 +7,16 @@ import { validator, Validators } from "../validation/index.js";
|
|
|
7
7
|
import { calculateExecuteFee } from "./fees.js";
|
|
8
8
|
import { loadWasmVM } from "../wasm/instance.js";
|
|
9
9
|
import { ProgramIdResolver } from "../config/ProgramIdResolver.js";
|
|
10
|
-
|
|
10
|
+
import { VmClusterConfigResolver } from "../config/VmClusterConfigResolver.js";
|
|
11
|
+
import { confirmTransactionRobust, getAccountInfoWithRetry, } from "../utils/transaction.js";
|
|
12
|
+
const DEFAULT_FEE_VAULT_SHARD_COUNT = (() => {
|
|
13
|
+
try {
|
|
14
|
+
return VmClusterConfigResolver.loadClusterConfig().feeVaultShardCount;
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return 2;
|
|
18
|
+
}
|
|
19
|
+
})();
|
|
11
20
|
const FEE_VAULT_NAMESPACE_SEED = Buffer.from([
|
|
12
21
|
0xff, 0x66, 0x69, 0x76, 0x65, 0x5f, 0x76, 0x6d, 0x5f, 0x66, 0x65, 0x65,
|
|
13
22
|
0x5f, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x76, 0x31,
|
|
@@ -24,7 +33,11 @@ async function readVMStateShardCount(connection, vmStateAddress) {
|
|
|
24
33
|
return DEFAULT_FEE_VAULT_SHARD_COUNT;
|
|
25
34
|
try {
|
|
26
35
|
const { PublicKey } = await import("@solana/web3.js");
|
|
27
|
-
const info = await connection
|
|
36
|
+
const info = await getAccountInfoWithRetry(connection, new PublicKey(vmStateAddress), {
|
|
37
|
+
commitment: "finalized",
|
|
38
|
+
retries: 2,
|
|
39
|
+
delayMs: 1000,
|
|
40
|
+
});
|
|
28
41
|
if (!info)
|
|
29
42
|
return DEFAULT_FEE_VAULT_SHARD_COUNT;
|
|
30
43
|
const data = new Uint8Array(info.data);
|
|
@@ -322,7 +335,7 @@ export async function generateExecuteInstruction(scriptAccount, functionName, pa
|
|
|
322
335
|
};
|
|
323
336
|
});
|
|
324
337
|
instructionAccounts.push(...userInstructionAccounts);
|
|
325
|
-
const instructionData = encodeExecuteInstruction(functionIndex, encodedParams, actualParamCount, feeShardIndex,
|
|
338
|
+
const instructionData = encodeExecuteInstruction(functionIndex, encodedParams, actualParamCount, feeShardIndex, options.debug === true);
|
|
326
339
|
// Runtime requires strict tail: [payer, fee_vault, system_program].
|
|
327
340
|
const signerCandidates = instructionAccounts
|
|
328
341
|
.filter((acc) => acc.isSigner)
|
|
@@ -444,15 +457,15 @@ export async function executeOnSolana(scriptAccount, connection, signerKeypair,
|
|
|
444
457
|
maxRetries: options.maxRetries || 3,
|
|
445
458
|
});
|
|
446
459
|
lastSignature = signature;
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
}
|
|
455
|
-
|
|
460
|
+
const latestBlockhash = await connection.getLatestBlockhash("confirmed");
|
|
461
|
+
const confirmation = await confirmTransactionRobust(connection, signature, {
|
|
462
|
+
commitment: "confirmed",
|
|
463
|
+
timeoutMs: 120000,
|
|
464
|
+
debug: options.debug,
|
|
465
|
+
blockhash,
|
|
466
|
+
lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
|
|
467
|
+
});
|
|
468
|
+
if (!confirmation.success) {
|
|
456
469
|
try {
|
|
457
470
|
const txDetails = await connection.getTransaction(signature, {
|
|
458
471
|
commitment: "confirmed",
|
|
@@ -479,9 +492,9 @@ export async function executeOnSolana(scriptAccount, connection, signerKeypair,
|
|
|
479
492
|
}
|
|
480
493
|
}
|
|
481
494
|
catch (getTransactionError) { }
|
|
482
|
-
throw
|
|
495
|
+
throw new Error(confirmation.error || "Execution confirmation failed");
|
|
483
496
|
}
|
|
484
|
-
if (confirmation.
|
|
497
|
+
if (confirmation.err) {
|
|
485
498
|
let logs = [];
|
|
486
499
|
let computeUnitsUsed;
|
|
487
500
|
try {
|
|
@@ -495,7 +508,7 @@ export async function executeOnSolana(scriptAccount, connection, signerKeypair,
|
|
|
495
508
|
}
|
|
496
509
|
}
|
|
497
510
|
catch { }
|
|
498
|
-
const errorMessage = `Execution transaction failed: ${JSON.stringify(confirmation.
|
|
511
|
+
const errorMessage = `Execution transaction failed: ${JSON.stringify(confirmation.err)}`;
|
|
499
512
|
return {
|
|
500
513
|
success: false,
|
|
501
514
|
error: errorMessage,
|
|
@@ -559,14 +572,13 @@ export async function executeScriptAccount(scriptAccount, functionIndex = 0, par
|
|
|
559
572
|
});
|
|
560
573
|
}
|
|
561
574
|
// Helpers
|
|
562
|
-
function encodeExecuteInstruction(functionIndex, encodedParams, paramCount, feeShardIndex,
|
|
575
|
+
function encodeExecuteInstruction(functionIndex, encodedParams, paramCount, feeShardIndex, debug = false) {
|
|
563
576
|
const parts = [];
|
|
564
577
|
parts.push(new Uint8Array([9]));
|
|
565
578
|
parts.push(new Uint8Array([
|
|
566
579
|
EXECUTE_FEE_HEADER_A,
|
|
567
580
|
EXECUTE_FEE_HEADER_B,
|
|
568
581
|
feeShardIndex & 0xff,
|
|
569
|
-
feeVaultBump & 0xff,
|
|
570
582
|
]));
|
|
571
583
|
// Function index as fixed u32
|
|
572
584
|
parts.push(encodeU32(functionIndex));
|
|
@@ -580,6 +592,15 @@ function encodeExecuteInstruction(functionIndex, encodedParams, paramCount, feeS
|
|
|
580
592
|
result.set(part, resultOffset);
|
|
581
593
|
resultOffset += part.length;
|
|
582
594
|
}
|
|
595
|
+
if (debug) {
|
|
596
|
+
const payloadLen = encodedParams.length;
|
|
597
|
+
const previewLen = Math.min(24, result.length);
|
|
598
|
+
const previewHex = Buffer.from(result.subarray(0, previewLen)).toString("hex");
|
|
599
|
+
const legacyVarintLikely = result.length >= 9 &&
|
|
600
|
+
// Legacy varint flow had no fee header and placed varint fields immediately after discriminator.
|
|
601
|
+
!(result[1] === EXECUTE_FEE_HEADER_A && result[2] === EXECUTE_FEE_HEADER_B);
|
|
602
|
+
console.log(`[FiveSDK] Execute wire envelope: discr=${result[0]} fee_header=[${result[1]},${result[2]},${result[3]}] function_index_u32=${functionIndex} param_count_u32=${paramCount} payload_len=${payloadLen} total_len=${result.length} preview_hex=${previewHex}${legacyVarintLikely ? " legacy_varint_suspected=true" : ""}`);
|
|
603
|
+
}
|
|
583
604
|
return result;
|
|
584
605
|
}
|
|
585
606
|
function encodeU32(value) {
|
|
@@ -625,21 +646,27 @@ async function encodeParametersWithABI(parameters, functionDef, functionIndex, _
|
|
|
625
646
|
const type = (param.type || param.param_type || '').toString().trim().toLowerCase();
|
|
626
647
|
return type === 'pubkey';
|
|
627
648
|
};
|
|
628
|
-
const paramDefs =
|
|
649
|
+
const paramDefs = functionDef.parameters || [];
|
|
629
650
|
const nonAccountParamDefs = paramDefs.filter((param) => !isAccountParam(param));
|
|
630
|
-
const
|
|
631
|
-
|
|
632
|
-
|
|
651
|
+
const isFullParamList = parameters.length === paramDefs.length;
|
|
652
|
+
const isArgOnlyList = parameters.length === nonAccountParamDefs.length;
|
|
653
|
+
if (!isFullParamList && !isArgOnlyList) {
|
|
654
|
+
console.warn(`[FiveSDK] Parameter validation warning: Function '${functionDef.name}' expects ${paramDefs.length} total params (${nonAccountParamDefs.length} non-account), but received ${parameters.length}.`);
|
|
633
655
|
}
|
|
656
|
+
// Current VM/compiler contract encodes non-account parameters only.
|
|
657
|
+
// If callers pass full ABI params (accounts + args), normalize to args-only order.
|
|
658
|
+
if (isFullParamList) {
|
|
659
|
+
console.warn(`[FiveSDK] Deprecation: full ABI parameter lists (including account params) are normalized to non-account execute args for '${functionDef.name}'. Pass args-only params to avoid this warning.`);
|
|
660
|
+
}
|
|
661
|
+
const defsForEncoding = nonAccountParamDefs;
|
|
634
662
|
const paramValues = {};
|
|
635
|
-
|
|
636
|
-
for (let index = 0; index <
|
|
637
|
-
const param =
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
if (sourceIndex >= parameters.length) {
|
|
663
|
+
const paramSourceIndexByName = new Map(paramDefs.map((param, index) => [param.name, index]));
|
|
664
|
+
for (let index = 0; index < defsForEncoding.length; index++) {
|
|
665
|
+
const param = defsForEncoding[index];
|
|
666
|
+
const sourceIndex = isFullParamList
|
|
667
|
+
? (paramSourceIndexByName.get(param.name) ?? -1)
|
|
668
|
+
: index;
|
|
669
|
+
if (sourceIndex < 0 || sourceIndex >= parameters.length) {
|
|
643
670
|
throw new Error(`Missing value for parameter: ${param.name}`);
|
|
644
671
|
}
|
|
645
672
|
let value = parameters[sourceIndex];
|
|
@@ -649,10 +676,9 @@ async function encodeParametersWithABI(parameters, functionDef, functionIndex, _
|
|
|
649
676
|
}
|
|
650
677
|
}
|
|
651
678
|
paramValues[param.name] = value;
|
|
652
|
-
argCursor += 1;
|
|
653
679
|
}
|
|
654
|
-
const encoded = await BytecodeEncoder.encodeExecute(functionIndex,
|
|
655
|
-
return { encoded, paramCount:
|
|
680
|
+
const encoded = await BytecodeEncoder.encodeExecute(functionIndex, defsForEncoding, paramValues, true, options);
|
|
681
|
+
return { encoded, paramCount: defsForEncoding.length };
|
|
656
682
|
}
|
|
657
683
|
function estimateComputeUnits(functionIndex, parameterCount) {
|
|
658
684
|
return Math.max(5000, 1000 + parameterCount * 500 + functionIndex * 100);
|
package/dist/modules/vm-state.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { PDAUtils, Base58Utils } from "../crypto/index.js";
|
|
2
2
|
import { ProgramIdResolver } from "../config/ProgramIdResolver.js";
|
|
3
|
+
import { getAccountInfoWithRetry } from "../utils/transaction.js";
|
|
3
4
|
export async function getVMState(connection, fiveVMProgramId) {
|
|
4
5
|
const programId = ProgramIdResolver.resolve(fiveVMProgramId);
|
|
5
6
|
const vmStatePDA = await PDAUtils.deriveVMStatePDA(programId);
|
|
@@ -12,7 +13,11 @@ export async function getVMState(connection, fiveVMProgramId) {
|
|
|
12
13
|
pubkey = new PublicKey(vmStatePDA.address);
|
|
13
14
|
}
|
|
14
15
|
catch { }
|
|
15
|
-
const info = await connection
|
|
16
|
+
const info = await getAccountInfoWithRetry(connection, pubkey, {
|
|
17
|
+
commitment: "finalized",
|
|
18
|
+
retries: 2,
|
|
19
|
+
delayMs: 1000,
|
|
20
|
+
});
|
|
16
21
|
if (!info)
|
|
17
22
|
throw new Error("VM State account not found");
|
|
18
23
|
accountData = new Uint8Array(info.data);
|
package/dist/project/config.js
CHANGED
|
@@ -22,7 +22,6 @@ export function parseProjectConfig(parsedToml) {
|
|
|
22
22
|
rpcUrl: deploy.rpc_url,
|
|
23
23
|
programId: deploy.program_id,
|
|
24
24
|
keypairPath: deploy.keypair_path,
|
|
25
|
-
multiFileMode: build.multi_file_mode ?? false,
|
|
26
25
|
optimizations: {
|
|
27
26
|
enableCompression: optimizations.enable_compression ?? true,
|
|
28
27
|
enableConstraintOptimization: optimizations.enable_constraint_optimization ?? true,
|
|
@@ -238,9 +238,14 @@ export class FiveTestRunner {
|
|
|
238
238
|
byFile.set(test.path, cases);
|
|
239
239
|
}
|
|
240
240
|
}
|
|
241
|
+
const moduleNameForFile = (file) => file
|
|
242
|
+
.replace(/\.v$/i, '')
|
|
243
|
+
.split(/[\\/]/)
|
|
244
|
+
.filter(Boolean)
|
|
245
|
+
.join('::');
|
|
241
246
|
for (const [file, testCases] of byFile.entries()) {
|
|
242
247
|
suites.push({
|
|
243
|
-
name:
|
|
248
|
+
name: moduleNameForFile(file),
|
|
244
249
|
description: `Tests from ${file}`,
|
|
245
250
|
testCases
|
|
246
251
|
});
|
package/dist/types.d.ts
CHANGED
|
@@ -18,7 +18,6 @@ export interface ProjectConfig {
|
|
|
18
18
|
keypairPath?: string;
|
|
19
19
|
optimizations?: ProjectOptimizations;
|
|
20
20
|
dependencies?: ProjectDependency[];
|
|
21
|
-
multiFileMode?: boolean;
|
|
22
21
|
wasm?: {
|
|
23
22
|
loader?: 'auto' | 'node' | 'bundler';
|
|
24
23
|
modulePaths?: string[];
|
|
@@ -80,12 +79,15 @@ export interface CompilationResult {
|
|
|
80
79
|
metadata?: CompilationMetadata;
|
|
81
80
|
errors?: CompilationError[];
|
|
82
81
|
warnings?: CompilationWarning[];
|
|
82
|
+
diagnostics?: CompilationError[];
|
|
83
83
|
disassembly?: string[];
|
|
84
84
|
metrics?: CompilationMetrics;
|
|
85
85
|
metricsReport?: CompilationMetricsReport;
|
|
86
86
|
fiveFile?: FiveCompiledFile;
|
|
87
87
|
publicFunctionNames?: string[];
|
|
88
88
|
functionNames?: string[] | FunctionNameEntry[];
|
|
89
|
+
formattedErrorsTerminal?: string;
|
|
90
|
+
formattedErrorsJson?: string;
|
|
89
91
|
}
|
|
90
92
|
export interface CompilationMetadata {
|
|
91
93
|
sourceFile: string;
|
|
@@ -113,7 +115,16 @@ export interface CompilationError {
|
|
|
113
115
|
category?: string;
|
|
114
116
|
description?: string;
|
|
115
117
|
location?: any;
|
|
116
|
-
suggestions?: string
|
|
118
|
+
suggestions?: Array<string | {
|
|
119
|
+
message: string;
|
|
120
|
+
explanation?: string;
|
|
121
|
+
confidence?: number;
|
|
122
|
+
codeSuggestion?: string;
|
|
123
|
+
}>;
|
|
124
|
+
sourceLine?: string;
|
|
125
|
+
sourceSnippet?: string;
|
|
126
|
+
rendered?: string;
|
|
127
|
+
raw?: any;
|
|
117
128
|
}
|
|
118
129
|
export interface CompilationWarning {
|
|
119
130
|
type: string;
|
|
@@ -332,12 +343,18 @@ export interface FiveCompiledFile {
|
|
|
332
343
|
}
|
|
333
344
|
export interface FiveFunction {
|
|
334
345
|
name: string;
|
|
346
|
+
index?: number;
|
|
335
347
|
parameters: FiveParameter[];
|
|
336
348
|
returnType?: FiveType;
|
|
337
349
|
}
|
|
338
350
|
export interface FiveParameter {
|
|
339
351
|
name: string;
|
|
340
352
|
type: FiveType;
|
|
353
|
+
param_type?: FiveType;
|
|
354
|
+
optional?: boolean;
|
|
355
|
+
is_account?: boolean;
|
|
356
|
+
isAccount?: boolean;
|
|
357
|
+
attributes?: string[];
|
|
341
358
|
}
|
|
342
359
|
export type FiveType = string;
|
|
343
360
|
export interface FunctionNameEntry {
|
package/dist/utils/abi.d.ts
CHANGED
|
@@ -4,7 +4,11 @@ export interface NormalizedABIFunction {
|
|
|
4
4
|
parameters: Array<{
|
|
5
5
|
name: string;
|
|
6
6
|
type: string;
|
|
7
|
+
param_type?: string;
|
|
7
8
|
optional?: boolean;
|
|
9
|
+
is_account?: boolean;
|
|
10
|
+
isAccount?: boolean;
|
|
11
|
+
attributes?: string[];
|
|
8
12
|
}>;
|
|
9
13
|
returnType?: string;
|
|
10
14
|
accounts?: any[];
|
package/dist/utils/abi.js
CHANGED
|
@@ -20,8 +20,11 @@ export function normalizeAbiFunctions(abiFunctions) {
|
|
|
20
20
|
parameters: parameters.map((param, paramIdx) => ({
|
|
21
21
|
name: param.name ?? `param${paramIdx}`,
|
|
22
22
|
type: param.type ?? param.param_type ?? param.paramType ?? '',
|
|
23
|
+
param_type: param.param_type ?? param.paramType,
|
|
23
24
|
optional: param.optional ?? false,
|
|
25
|
+
is_account: param.is_account ?? param.isAccount ?? false,
|
|
24
26
|
isAccount: param.isAccount ?? param.is_account ?? false,
|
|
27
|
+
attributes: Array.isArray(param.attributes) ? [...param.attributes] : [],
|
|
25
28
|
})),
|
|
26
29
|
returnType: func.returnType ?? func.return_type,
|
|
27
30
|
accounts: func.accounts ?? [],
|
|
@@ -1,5 +1,27 @@
|
|
|
1
|
+
export declare const SDK_COMMITMENTS: {
|
|
2
|
+
readonly WRITE: "confirmed";
|
|
3
|
+
readonly READ: "finalized";
|
|
4
|
+
readonly CONFIRM: "finalized";
|
|
5
|
+
};
|
|
1
6
|
export declare function pollForConfirmation(connection: any, signature: string, commitment?: string, timeoutMs?: number, debug?: boolean): Promise<{
|
|
2
7
|
success: boolean;
|
|
3
8
|
err?: any;
|
|
4
9
|
error?: string;
|
|
5
10
|
}>;
|
|
11
|
+
export declare function confirmTransactionRobust(connection: any, signature: string, options?: {
|
|
12
|
+
commitment?: string;
|
|
13
|
+
timeoutMs?: number;
|
|
14
|
+
debug?: boolean;
|
|
15
|
+
blockhash?: string;
|
|
16
|
+
lastValidBlockHeight?: number;
|
|
17
|
+
}): Promise<{
|
|
18
|
+
success: boolean;
|
|
19
|
+
err?: any;
|
|
20
|
+
error?: string;
|
|
21
|
+
}>;
|
|
22
|
+
export declare function getAccountInfoWithRetry(connection: any, pubkey: any, options?: {
|
|
23
|
+
commitment?: string;
|
|
24
|
+
retries?: number;
|
|
25
|
+
delayMs?: number;
|
|
26
|
+
debug?: boolean;
|
|
27
|
+
}): Promise<any | null>;
|
|
@@ -1,6 +1,40 @@
|
|
|
1
|
+
export const SDK_COMMITMENTS = {
|
|
2
|
+
WRITE: "confirmed",
|
|
3
|
+
READ: "finalized",
|
|
4
|
+
CONFIRM: "finalized",
|
|
5
|
+
};
|
|
6
|
+
const DEFAULT_POLL_INTERVAL_MS = 1000;
|
|
7
|
+
const DEFAULT_RETRY_DELAY_MS = 700;
|
|
8
|
+
async function sleep(ms) {
|
|
9
|
+
await new Promise(resolve => setTimeout(resolve, ms));
|
|
10
|
+
}
|
|
11
|
+
function backoffDelayMs(baseMs, attempt) {
|
|
12
|
+
const exp = Math.min(attempt, 6);
|
|
13
|
+
const raw = baseMs * (2 ** exp);
|
|
14
|
+
const jitter = Math.floor(raw * (0.15 * Math.random()));
|
|
15
|
+
return raw + jitter;
|
|
16
|
+
}
|
|
17
|
+
function normalizeCommitment(commitment) {
|
|
18
|
+
if (commitment === "finalized")
|
|
19
|
+
return "finalized";
|
|
20
|
+
if (commitment === "processed")
|
|
21
|
+
return "processed";
|
|
22
|
+
return "confirmed";
|
|
23
|
+
}
|
|
24
|
+
function statusMeetsCommitment(status, confirmations, target) {
|
|
25
|
+
if (target === "processed") {
|
|
26
|
+
return !!status || (confirmations ?? 0) >= 0;
|
|
27
|
+
}
|
|
28
|
+
if (target === "confirmed") {
|
|
29
|
+
return status === "confirmed" || status === "finalized" || (confirmations ?? 0) >= 1;
|
|
30
|
+
}
|
|
31
|
+
// finalized must be explicitly finalized; confirmations count is insufficient.
|
|
32
|
+
return status === "finalized";
|
|
33
|
+
}
|
|
1
34
|
export async function pollForConfirmation(connection, signature, commitment = "confirmed", timeoutMs = 120000, debug = false) {
|
|
2
35
|
const startTime = Date.now();
|
|
3
|
-
const pollIntervalMs =
|
|
36
|
+
const pollIntervalMs = DEFAULT_POLL_INTERVAL_MS;
|
|
37
|
+
const targetCommitment = normalizeCommitment(commitment);
|
|
4
38
|
if (debug) {
|
|
5
39
|
console.log(`[FiveSDK] Starting confirmation poll with ${timeoutMs}ms timeout`);
|
|
6
40
|
}
|
|
@@ -11,30 +45,36 @@ export async function pollForConfirmation(connection, signature, commitment = "c
|
|
|
11
45
|
console.log(`[FiveSDK] Confirmation status: ${JSON.stringify(confirmationStatus.value)}`);
|
|
12
46
|
}
|
|
13
47
|
if (confirmationStatus.value) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
48
|
+
const transactionError = confirmationStatus.value.err;
|
|
49
|
+
if (transactionError) {
|
|
50
|
+
if (debug) {
|
|
51
|
+
console.log(`[FiveSDK] Transaction error: ${JSON.stringify(transactionError)}`);
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
success: false,
|
|
55
|
+
err: transactionError,
|
|
56
|
+
error: JSON.stringify(transactionError),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
if (statusMeetsCommitment(confirmationStatus.value.confirmationStatus, confirmationStatus.value.confirmations, targetCommitment)) {
|
|
60
|
+
const succeeded = true;
|
|
18
61
|
if (debug) {
|
|
19
62
|
console.log(`[FiveSDK] Transaction confirmed after ${Date.now() - startTime}ms${succeeded ? '' : ' (with error)'}`);
|
|
20
|
-
if (transactionError) {
|
|
21
|
-
console.log(`[FiveSDK] Transaction error: ${JSON.stringify(transactionError)}`);
|
|
22
|
-
}
|
|
23
63
|
}
|
|
24
64
|
return {
|
|
25
65
|
success: succeeded,
|
|
26
|
-
err:
|
|
27
|
-
error:
|
|
66
|
+
err: undefined,
|
|
67
|
+
error: undefined,
|
|
28
68
|
};
|
|
29
69
|
}
|
|
30
70
|
}
|
|
31
|
-
await
|
|
71
|
+
await sleep(pollIntervalMs);
|
|
32
72
|
}
|
|
33
73
|
catch (error) {
|
|
34
74
|
if (debug) {
|
|
35
75
|
console.log(`[FiveSDK] Polling error: ${error instanceof Error ? error.message : String(error)}`);
|
|
36
76
|
}
|
|
37
|
-
await
|
|
77
|
+
await sleep(pollIntervalMs);
|
|
38
78
|
}
|
|
39
79
|
}
|
|
40
80
|
const elapsed = Date.now() - startTime;
|
|
@@ -46,3 +86,45 @@ export async function pollForConfirmation(connection, signature, commitment = "c
|
|
|
46
86
|
error: `Transaction confirmation timeout after ${elapsed}ms. Signature: ${signature}`,
|
|
47
87
|
};
|
|
48
88
|
}
|
|
89
|
+
export async function confirmTransactionRobust(connection, signature, options = {}) {
|
|
90
|
+
const commitment = options.commitment || SDK_COMMITMENTS.CONFIRM;
|
|
91
|
+
const timeoutMs = options.timeoutMs || 120000;
|
|
92
|
+
const debug = options.debug || false;
|
|
93
|
+
try {
|
|
94
|
+
const confirmArg = options.blockhash && typeof options.lastValidBlockHeight === "number"
|
|
95
|
+
? {
|
|
96
|
+
signature,
|
|
97
|
+
blockhash: options.blockhash,
|
|
98
|
+
lastValidBlockHeight: options.lastValidBlockHeight,
|
|
99
|
+
}
|
|
100
|
+
: signature;
|
|
101
|
+
const confirmation = await connection.confirmTransaction(confirmArg, commitment);
|
|
102
|
+
const err = confirmation?.value?.err;
|
|
103
|
+
if (!err) {
|
|
104
|
+
return { success: true };
|
|
105
|
+
}
|
|
106
|
+
return { success: false, err, error: JSON.stringify(err) };
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
if (debug) {
|
|
110
|
+
console.log(`[FiveSDK] confirmTransaction threw, falling back to polling: ${error instanceof Error ? error.message : String(error)}`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return pollForConfirmation(connection, signature, commitment, timeoutMs, debug);
|
|
114
|
+
}
|
|
115
|
+
export async function getAccountInfoWithRetry(connection, pubkey, options = {}) {
|
|
116
|
+
const commitment = options.commitment || SDK_COMMITMENTS.READ;
|
|
117
|
+
const retries = options.retries ?? 2;
|
|
118
|
+
const delayMs = options.delayMs ?? DEFAULT_RETRY_DELAY_MS;
|
|
119
|
+
const debug = options.debug || false;
|
|
120
|
+
let info = await connection.getAccountInfo(pubkey, commitment);
|
|
121
|
+
for (let attempt = 0; !info && attempt < retries; attempt++) {
|
|
122
|
+
const waitMs = backoffDelayMs(delayMs, attempt);
|
|
123
|
+
if (debug) {
|
|
124
|
+
console.log(`[FiveSDK] getAccountInfo retry ${attempt + 1}/${retries}, waiting ${waitMs}ms`);
|
|
125
|
+
}
|
|
126
|
+
await sleep(waitMs);
|
|
127
|
+
info = await connection.getAccountInfo(pubkey, commitment);
|
|
128
|
+
}
|
|
129
|
+
return info;
|
|
130
|
+
}
|
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
import { CompilationOptions, CompilationResult } from "../../types.js";
|
|
2
2
|
import { CompilationContext } from "./types.js";
|
|
3
3
|
export declare function compile(ctx: CompilationContext, source: string, options?: any): Promise<any>;
|
|
4
|
-
export declare function compileModules(ctx: CompilationContext, mainSource: string, modules: Array<{
|
|
5
|
-
name: string;
|
|
6
|
-
source: string;
|
|
7
|
-
}>, options?: any): Promise<any>;
|
|
8
4
|
export declare function compileFile(ctx: CompilationContext, options: CompilationOptions): Promise<CompilationResult>;
|
|
9
5
|
export declare function compileWithDiscovery(ctx: CompilationContext, entryPoint: string, options?: any): Promise<any>;
|
|
10
|
-
export declare function compileModulesExplicit(ctx: CompilationContext, moduleFiles: string[], entryPoint: string, options?: any): Promise<any>;
|