@5ive-tech/sdk 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +279 -0
- package/dist/FiveSDK.d.ts +336 -0
- package/dist/FiveSDK.js +395 -0
- package/dist/accounts/index.d.ts +254 -0
- package/dist/accounts/index.js +543 -0
- package/dist/assets/vm/dummy.file +0 -0
- package/dist/assets/vm/five_vm_wasm.d.ts +762 -0
- package/dist/assets/vm/five_vm_wasm.js +3754 -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 +247 -0
- package/dist/assets/vm/package.json +11 -0
- package/dist/bin/gen-types.d.ts +2 -0
- package/dist/bin/gen-types.js +35 -0
- package/dist/compiler/BytecodeCompiler.d.ts +83 -0
- package/dist/compiler/BytecodeCompiler.js +379 -0
- package/dist/config/ConfigManager.d.ts +13 -0
- package/dist/config/ConfigManager.js +27 -0
- package/dist/config/ProgramIdResolver.d.ts +62 -0
- package/dist/config/ProgramIdResolver.js +104 -0
- package/dist/crypto/index.d.ts +211 -0
- package/dist/crypto/index.js +451 -0
- package/dist/encoding/ParameterEncoder.d.ts +31 -0
- package/dist/encoding/ParameterEncoder.js +278 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +28 -0
- package/dist/lib/bytecode-encoder.d.ts +62 -0
- package/dist/lib/bytecode-encoder.js +281 -0
- package/dist/logging/index.d.ts +9 -0
- package/dist/logging/index.js +10 -0
- package/dist/metadata/index.d.ts +213 -0
- package/dist/metadata/index.js +296 -0
- package/dist/modules/accounts.d.ts +60 -0
- package/dist/modules/accounts.js +275 -0
- package/dist/modules/deploy.d.ts +90 -0
- package/dist/modules/deploy.js +1118 -0
- package/dist/modules/execute.d.ts +90 -0
- package/dist/modules/execute.js +649 -0
- package/dist/modules/fees.d.ts +14 -0
- package/dist/modules/fees.js +112 -0
- package/dist/modules/namespaces.d.ts +39 -0
- package/dist/modules/namespaces.js +190 -0
- package/dist/modules/state-diff.d.ts +35 -0
- package/dist/modules/state-diff.js +342 -0
- package/dist/modules/vm-state.d.ts +7 -0
- package/dist/modules/vm-state.js +44 -0
- package/dist/program/AccountResolver.d.ts +67 -0
- package/dist/program/AccountResolver.js +134 -0
- package/dist/program/BorshSchemaGenerator.d.ts +8 -0
- package/dist/program/BorshSchemaGenerator.js +57 -0
- package/dist/program/FiveProgram.d.ts +144 -0
- package/dist/program/FiveProgram.js +282 -0
- package/dist/program/FunctionBuilder.d.ts +114 -0
- package/dist/program/FunctionBuilder.js +347 -0
- package/dist/program/ProgramAccount.d.ts +38 -0
- package/dist/program/ProgramAccount.js +170 -0
- package/dist/program/TypeGenerator.d.ts +90 -0
- package/dist/program/TypeGenerator.js +195 -0
- package/dist/program/index.d.ts +24 -0
- package/dist/program/index.js +21 -0
- package/dist/project/config.d.ts +5 -0
- package/dist/project/config.js +33 -0
- package/dist/project/toml.d.ts +6 -0
- package/dist/project/toml.js +43 -0
- package/dist/project/workspace.d.ts +160 -0
- package/dist/project/workspace.js +73 -0
- package/dist/testing/AccountMetaGenerator.d.ts +121 -0
- package/dist/testing/AccountMetaGenerator.js +261 -0
- package/dist/testing/AccountTestFixture.d.ts +211 -0
- package/dist/testing/AccountTestFixture.js +530 -0
- package/dist/testing/OnChainAccountManager.d.ts +81 -0
- package/dist/testing/OnChainAccountManager.js +260 -0
- package/dist/testing/StateSerializer.d.ts +65 -0
- package/dist/testing/StateSerializer.js +330 -0
- package/dist/testing/TestDiscovery.d.ts +79 -0
- package/dist/testing/TestDiscovery.js +274 -0
- package/dist/testing/TestRunner.d.ts +117 -0
- package/dist/testing/TestRunner.js +346 -0
- package/dist/testing/index.d.ts +14 -0
- package/dist/testing/index.js +13 -0
- package/dist/types.d.ts +356 -0
- package/dist/types.js +32 -0
- package/dist/utils/abi.d.ts +31 -0
- package/dist/utils/abi.js +92 -0
- package/dist/utils/transaction.d.ts +5 -0
- package/dist/utils/transaction.js +48 -0
- package/dist/validation/InputValidator.d.ts +142 -0
- package/dist/validation/InputValidator.js +332 -0
- package/dist/validation/index.d.ts +4 -0
- package/dist/validation/index.js +4 -0
- package/dist/wasm/compiler/AbiLogic.d.ts +4 -0
- package/dist/wasm/compiler/AbiLogic.js +37 -0
- package/dist/wasm/compiler/AnalysisLogic.d.ts +6 -0
- package/dist/wasm/compiler/AnalysisLogic.js +61 -0
- package/dist/wasm/compiler/CompilationLogic.d.ts +10 -0
- package/dist/wasm/compiler/CompilationLogic.js +431 -0
- package/dist/wasm/compiler/FiveCompiler.d.ts +48 -0
- package/dist/wasm/compiler/FiveCompiler.js +183 -0
- package/dist/wasm/compiler/InfoLogic.d.ts +6 -0
- package/dist/wasm/compiler/InfoLogic.js +24 -0
- package/dist/wasm/compiler/OptimizationLogic.d.ts +2 -0
- package/dist/wasm/compiler/OptimizationLogic.js +13 -0
- package/dist/wasm/compiler/ValidationLogic.d.ts +7 -0
- package/dist/wasm/compiler/ValidationLogic.js +26 -0
- package/dist/wasm/compiler/index.d.ts +2 -0
- package/dist/wasm/compiler/index.js +2 -0
- package/dist/wasm/compiler/types.d.ts +8 -0
- package/dist/wasm/compiler/types.js +1 -0
- package/dist/wasm/compiler/utils.d.ts +8 -0
- package/dist/wasm/compiler/utils.js +75 -0
- package/dist/wasm/index.d.ts +9 -0
- package/dist/wasm/index.js +12 -0
- package/dist/wasm/instance.d.ts +1 -0
- package/dist/wasm/instance.js +26 -0
- package/dist/wasm/loader.d.ts +7 -0
- package/dist/wasm/loader.js +112 -0
- package/dist/wasm/vm.d.ts +33 -0
- package/dist/wasm/vm.js +250 -0
- package/package.json +59 -0
package/dist/FiveSDK.js
ADDED
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Five SDK client for Five VM scripts.
|
|
3
|
+
*/
|
|
4
|
+
import { FiveSDKError, } from "./types.js";
|
|
5
|
+
import { BytecodeCompiler } from "./compiler/BytecodeCompiler.js";
|
|
6
|
+
import { ParameterEncoder } from "./encoding/ParameterEncoder.js";
|
|
7
|
+
import { ScriptMetadataParser, MetadataCache, } from "./metadata/index.js";
|
|
8
|
+
import { normalizeAbiFunctions, resolveFunctionIndex } from "./utils/abi.js";
|
|
9
|
+
import { validator, Validators } from "./validation/index.js";
|
|
10
|
+
import { ProgramIdResolver } from "./config/ProgramIdResolver.js";
|
|
11
|
+
import * as Deploy from "./modules/deploy.js";
|
|
12
|
+
import * as Execute from "./modules/execute.js";
|
|
13
|
+
import * as Fees from "./modules/fees.js";
|
|
14
|
+
import * as VMState from "./modules/vm-state.js";
|
|
15
|
+
import * as Accounts from "./modules/accounts.js";
|
|
16
|
+
import * as StateDiff from "./modules/state-diff.js";
|
|
17
|
+
import * as Namespaces from "./modules/namespaces.js";
|
|
18
|
+
/**
|
|
19
|
+
* Main Five SDK class - entry point for all Five VM interactions
|
|
20
|
+
*/
|
|
21
|
+
export class FiveSDK {
|
|
22
|
+
constructor(config = {}) {
|
|
23
|
+
// Store the config but resolve at call time
|
|
24
|
+
this.fiveVMProgramId = config.fiveVMProgramId;
|
|
25
|
+
this.debug = config.debug || false;
|
|
26
|
+
this.network = config.network;
|
|
27
|
+
if (this.debug) {
|
|
28
|
+
const resolved = ProgramIdResolver.resolveOptional(this.fiveVMProgramId);
|
|
29
|
+
if (resolved) {
|
|
30
|
+
console.log(`[FiveSDK] Initialized with Five VM Program: ${resolved}`);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
console.log(`[FiveSDK] Initialized (program ID will be resolved at call time)`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
getConfig() {
|
|
38
|
+
return {
|
|
39
|
+
fiveVMProgramId: this.fiveVMProgramId,
|
|
40
|
+
debug: this.debug,
|
|
41
|
+
network: this.network,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
static async initializeComponents(debug = false) {
|
|
45
|
+
if (!this.compiler) {
|
|
46
|
+
this.compiler = new BytecodeCompiler({ debug });
|
|
47
|
+
}
|
|
48
|
+
if (!this.parameterEncoder) {
|
|
49
|
+
this.parameterEncoder = new ParameterEncoder(debug);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// ==================== Static Factory Methods ====================
|
|
53
|
+
static create(options = {}) {
|
|
54
|
+
return new FiveSDK(options);
|
|
55
|
+
}
|
|
56
|
+
static devnet(options = {}) {
|
|
57
|
+
return new FiveSDK({ ...options, network: "devnet" });
|
|
58
|
+
}
|
|
59
|
+
static mainnet(options = {}) {
|
|
60
|
+
return new FiveSDK({ ...options, network: "mainnet" });
|
|
61
|
+
}
|
|
62
|
+
static localnet(options = {}) {
|
|
63
|
+
return new FiveSDK({ ...options, network: "localnet" });
|
|
64
|
+
}
|
|
65
|
+
// ==================== Program ID Defaults ====================
|
|
66
|
+
/**
|
|
67
|
+
* Set the default program ID for all SDK instances and operations
|
|
68
|
+
* Useful when deploying to a known program ID across your application
|
|
69
|
+
* @param programId - Solana public key (base58 encoded)
|
|
70
|
+
*/
|
|
71
|
+
static setDefaultProgramId(programId) {
|
|
72
|
+
ProgramIdResolver.setDefault(programId);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Get the currently set default program ID
|
|
76
|
+
* @returns The default program ID, or undefined if not set
|
|
77
|
+
*/
|
|
78
|
+
static getDefaultProgramId() {
|
|
79
|
+
return ProgramIdResolver.getDefault();
|
|
80
|
+
}
|
|
81
|
+
// ==================== Namespaces ====================
|
|
82
|
+
static canonicalizeNamespace(value) {
|
|
83
|
+
return Namespaces.canonicalizeScopedNamespace(value);
|
|
84
|
+
}
|
|
85
|
+
static namespaceSeedBytes(value) {
|
|
86
|
+
return Namespaces.namespaceSeedBytes(value);
|
|
87
|
+
}
|
|
88
|
+
static resolveNamespaceFromLockfile(value, lockfile) {
|
|
89
|
+
return Namespaces.resolveNamespaceFromLockfile(value, lockfile);
|
|
90
|
+
}
|
|
91
|
+
static async deriveNamespaceAccounts(value, fiveVMProgramId) {
|
|
92
|
+
return Namespaces.deriveNamespaceAccounts(value, fiveVMProgramId);
|
|
93
|
+
}
|
|
94
|
+
static async registerNamespaceTldOnChain(namespaceValue, options) {
|
|
95
|
+
return Namespaces.registerNamespaceTldOnChain(namespaceValue, options);
|
|
96
|
+
}
|
|
97
|
+
static async bindNamespaceOnChain(namespaceValue, scriptAccount, options) {
|
|
98
|
+
return Namespaces.bindNamespaceOnChain(namespaceValue, scriptAccount, options);
|
|
99
|
+
}
|
|
100
|
+
static async resolveNamespaceOnChain(namespaceValue, options) {
|
|
101
|
+
return Namespaces.resolveNamespaceOnChain(namespaceValue, options);
|
|
102
|
+
}
|
|
103
|
+
// ==================== Script Compilation ====================
|
|
104
|
+
static async compile(source, options = {}) {
|
|
105
|
+
const sourceContent = typeof source === 'string' ? source : source.content;
|
|
106
|
+
const sourceFilename = typeof source === 'string' ? 'unknown.v' : source.filename || 'unknown.v';
|
|
107
|
+
Validators.sourceCode(sourceContent);
|
|
108
|
+
Validators.options(options);
|
|
109
|
+
await this.initializeComponents(options.debug);
|
|
110
|
+
try {
|
|
111
|
+
const result = await this.compiler.compile(source, options);
|
|
112
|
+
if (result.success && result.bytecode) {
|
|
113
|
+
let abiData = result.abi ?? { functions: [], fields: [] };
|
|
114
|
+
if (options.debug) {
|
|
115
|
+
try {
|
|
116
|
+
const generatedABI = await this.compiler.generateABI(source);
|
|
117
|
+
if (generatedABI && generatedABI.functions) {
|
|
118
|
+
abiData = generatedABI;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
catch (abiError) {
|
|
122
|
+
console.warn("[FiveSDK] ABI generation failed:", abiError);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
const functions = normalizeAbiFunctions(abiData.functions ?? abiData)
|
|
126
|
+
.map((func) => ({
|
|
127
|
+
name: func.name,
|
|
128
|
+
index: func.index,
|
|
129
|
+
parameters: func.parameters?.map((param) => ({
|
|
130
|
+
name: param.name,
|
|
131
|
+
type: param.type,
|
|
132
|
+
optional: param.optional ?? false,
|
|
133
|
+
})) || [],
|
|
134
|
+
returnType: func.returnType,
|
|
135
|
+
}));
|
|
136
|
+
result.fiveFile = {
|
|
137
|
+
filename: sourceFilename,
|
|
138
|
+
bytecode: Buffer.from(result.bytecode).toString("base64"),
|
|
139
|
+
abi: {
|
|
140
|
+
functions,
|
|
141
|
+
fields: abiData.fields || [],
|
|
142
|
+
version: "1.0",
|
|
143
|
+
},
|
|
144
|
+
disassembly: result.disassembly || [],
|
|
145
|
+
metrics: options.includeMetrics ? result.metrics : undefined,
|
|
146
|
+
version: "1.0",
|
|
147
|
+
};
|
|
148
|
+
if (result.bytecode) {
|
|
149
|
+
const functionNames = await this.getFunctionNames(result.bytecode);
|
|
150
|
+
result.functionNames = functionNames;
|
|
151
|
+
result.publicFunctionNames = functionNames.map((f) => f.name);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return result;
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
throw new FiveSDKError(`Compilation failed: ${error instanceof Error ? error.message : "Unknown error"}`, "COMPILATION_ERROR");
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
static async compileModules(mainSource, modules, options = {}) {
|
|
161
|
+
const mainSourceObj = typeof mainSource === 'string' ? { content: mainSource, filename: 'main.v' } : mainSource;
|
|
162
|
+
Validators.options(options);
|
|
163
|
+
await this.initializeComponents(options.debug);
|
|
164
|
+
if (!this.compiler)
|
|
165
|
+
throw new FiveSDKError("Compiler not initialized", "COMPILER_ERROR");
|
|
166
|
+
return this.compiler.compileModules(mainSourceObj, modules, options);
|
|
167
|
+
}
|
|
168
|
+
static async compileWithDiscovery(entryPoint, options = {}) {
|
|
169
|
+
Validators.options(options);
|
|
170
|
+
await this.initializeComponents(options.debug);
|
|
171
|
+
if (typeof this.compiler.compileWithDiscovery === 'function') {
|
|
172
|
+
return this.compiler.compileWithDiscovery(entryPoint, options);
|
|
173
|
+
}
|
|
174
|
+
return this.compileFile(entryPoint, options);
|
|
175
|
+
}
|
|
176
|
+
static async discoverModules(entryPoint, options = {}) {
|
|
177
|
+
await this.initializeComponents(options.debug);
|
|
178
|
+
if (typeof this.compiler.discoverModules === 'function') {
|
|
179
|
+
return this.compiler.discoverModules(entryPoint);
|
|
180
|
+
}
|
|
181
|
+
throw new Error("discoverModules not available in current compiler version");
|
|
182
|
+
}
|
|
183
|
+
static async compileFile(filePath, options = {}) {
|
|
184
|
+
Validators.filePath(filePath);
|
|
185
|
+
Validators.options(options);
|
|
186
|
+
await this.initializeComponents(options.debug);
|
|
187
|
+
return this.compiler.compileFile(filePath, options);
|
|
188
|
+
}
|
|
189
|
+
// ==================== Five File Format Utilities ====================
|
|
190
|
+
static async loadFiveFile(fileContent) {
|
|
191
|
+
try {
|
|
192
|
+
const fiveFile = JSON.parse(fileContent);
|
|
193
|
+
if (!fiveFile.bytecode || !fiveFile.abi) {
|
|
194
|
+
throw new Error("Invalid .five file format: missing bytecode or ABI");
|
|
195
|
+
}
|
|
196
|
+
const bytecode = new Uint8Array(Buffer.from(fiveFile.bytecode, "base64"));
|
|
197
|
+
return { bytecode, abi: fiveFile.abi, debug: fiveFile.debug };
|
|
198
|
+
}
|
|
199
|
+
catch (error) {
|
|
200
|
+
throw new FiveSDKError(`Failed to load .five file: ${error instanceof Error ? error.message : "Unknown error"}`, "FILE_LOAD_ERROR");
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
static extractBytecode(fiveFile) {
|
|
204
|
+
return new Uint8Array(Buffer.from(fiveFile.bytecode, "base64"));
|
|
205
|
+
}
|
|
206
|
+
static resolveFunctionIndex(abi, functionName) {
|
|
207
|
+
return resolveFunctionIndex(abi, functionName);
|
|
208
|
+
}
|
|
209
|
+
// ==================== WASM VM Direct Execution ====================
|
|
210
|
+
static async executeLocally(bytecode, functionName, parameters = [], options = {}) {
|
|
211
|
+
return Execute.executeLocally(bytecode, functionName, parameters, options);
|
|
212
|
+
}
|
|
213
|
+
static async execute(source, functionName, parameters = [], options = {}) {
|
|
214
|
+
await this.initializeComponents(options.debug);
|
|
215
|
+
return Execute.execute(this.compiler, source, functionName, parameters, options);
|
|
216
|
+
}
|
|
217
|
+
static async validateBytecode(bytecode, options = {}) {
|
|
218
|
+
Validators.bytecode(bytecode);
|
|
219
|
+
Validators.options(options);
|
|
220
|
+
await this.initializeComponents(options.debug);
|
|
221
|
+
// Using compile's validateSource? No, validateBytecode logic is in FiveSDK using loadWasmVM.
|
|
222
|
+
// I moved loadWasmVM to instance.ts but validateBytecode logic was in FiveSDK.
|
|
223
|
+
// I should have moved validateBytecode logic to execute.ts or validation/index.ts or a new module.
|
|
224
|
+
// I forgot to move `validateBytecode`. It was in `FiveSDK.ts`.
|
|
225
|
+
// I can invoke `loadWasmVM` here and call it.
|
|
226
|
+
try {
|
|
227
|
+
const { loadWasmVM } = await import("./wasm/instance.js");
|
|
228
|
+
const wasmVM = await loadWasmVM();
|
|
229
|
+
return await wasmVM.validateBytecode(bytecode);
|
|
230
|
+
}
|
|
231
|
+
catch (error) {
|
|
232
|
+
return {
|
|
233
|
+
valid: false,
|
|
234
|
+
errors: [error instanceof Error ? error.message : "Unknown validation error"],
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
// ==================== Deployment ====================
|
|
239
|
+
static async generateDeployInstruction(bytecode, deployer, options = {}, connection) {
|
|
240
|
+
return Deploy.generateDeployInstruction(bytecode, deployer, options, connection);
|
|
241
|
+
}
|
|
242
|
+
// ==================== Execution ====================
|
|
243
|
+
static async generateExecuteInstruction(scriptAccount, functionName, parameters = [], accounts = [], connection, options = {}) {
|
|
244
|
+
return Execute.generateExecuteInstruction(scriptAccount, functionName, parameters, accounts, connection, options);
|
|
245
|
+
}
|
|
246
|
+
// ==================== VM State & Fees ====================
|
|
247
|
+
static async getVMState(connection, fiveVMProgramId) {
|
|
248
|
+
return VMState.getVMState(connection, fiveVMProgramId);
|
|
249
|
+
}
|
|
250
|
+
static async getFees(connection, fiveVMProgramId) {
|
|
251
|
+
return Fees.getFees(connection, fiveVMProgramId);
|
|
252
|
+
}
|
|
253
|
+
static async calculateDeployFee(bytecodeSize, connection, fiveVMProgramId) {
|
|
254
|
+
return Fees.calculateDeployFee(bytecodeSize, connection, fiveVMProgramId);
|
|
255
|
+
}
|
|
256
|
+
static async calculateExecuteFee(connection, fiveVMProgramId) {
|
|
257
|
+
return Fees.calculateExecuteFee(connection, fiveVMProgramId);
|
|
258
|
+
}
|
|
259
|
+
static async getFeeInformation(bytecodeSize, connection, fiveVMProgramId) {
|
|
260
|
+
return Fees.getFeeInformation(bytecodeSize, connection, fiveVMProgramId);
|
|
261
|
+
}
|
|
262
|
+
// ==================== Script Analysis ====================
|
|
263
|
+
static async getScriptMetadata(scriptAccount, connection) {
|
|
264
|
+
validator.validateBase58Address(scriptAccount, "scriptAccount");
|
|
265
|
+
if (!connection)
|
|
266
|
+
throw new Error("No connection provided");
|
|
267
|
+
const metadata = await ScriptMetadataParser.getScriptMetadata(connection, scriptAccount);
|
|
268
|
+
const normalizedFunctions = normalizeAbiFunctions(metadata.abi?.functions ?? metadata.abi);
|
|
269
|
+
return {
|
|
270
|
+
functions: normalizedFunctions.map((func) => ({
|
|
271
|
+
name: func.name,
|
|
272
|
+
index: func.index,
|
|
273
|
+
parameters: func.parameters,
|
|
274
|
+
returnType: func.returnType,
|
|
275
|
+
visibility: func.visibility,
|
|
276
|
+
})),
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
static async getScriptMetadataWithConnection(scriptAccount, connection) {
|
|
280
|
+
validator.validateBase58Address(scriptAccount, "scriptAccount");
|
|
281
|
+
return ScriptMetadataParser.getScriptMetadata(connection, scriptAccount);
|
|
282
|
+
}
|
|
283
|
+
static parseScriptMetadata(accountData, address) {
|
|
284
|
+
Validators.bytecode(accountData);
|
|
285
|
+
validator.validateBase58Address(address, "address");
|
|
286
|
+
return ScriptMetadataParser.parseMetadata(accountData, address);
|
|
287
|
+
}
|
|
288
|
+
static async getCachedScriptMetadata(scriptAccount, connection, cacheTTL = 5 * 60 * 1000) {
|
|
289
|
+
validator.validateBase58Address(scriptAccount, "scriptAccount");
|
|
290
|
+
validator.validateNumber(cacheTTL, "cacheTTL");
|
|
291
|
+
return this.metadataCache.getMetadata(scriptAccount, (address) => ScriptMetadataParser.getScriptMetadata(connection, address), cacheTTL);
|
|
292
|
+
}
|
|
293
|
+
static invalidateMetadataCache(scriptAccount) {
|
|
294
|
+
validator.validateBase58Address(scriptAccount, "scriptAccount");
|
|
295
|
+
this.metadataCache.invalidate(scriptAccount);
|
|
296
|
+
}
|
|
297
|
+
static getMetadataCacheStats() {
|
|
298
|
+
return this.metadataCache.getStats();
|
|
299
|
+
}
|
|
300
|
+
// ==================== Utilities ====================
|
|
301
|
+
static async executeOnSolana(scriptAccount, connection, signerKeypair, functionName, parameters = [], accounts = [], options = {}) {
|
|
302
|
+
return Execute.executeOnSolana(scriptAccount, connection, signerKeypair, functionName, parameters, accounts, options);
|
|
303
|
+
}
|
|
304
|
+
static async executeScriptAccount(scriptAccount, functionIndex = 0, parameters = [], connection, signerKeypair, options = {}) {
|
|
305
|
+
return Execute.executeScriptAccount(scriptAccount, functionIndex, parameters, connection, signerKeypair, options);
|
|
306
|
+
}
|
|
307
|
+
static async getFunctionNames(bytecode) {
|
|
308
|
+
await this.initializeComponents(false);
|
|
309
|
+
try {
|
|
310
|
+
const namesJson = await this.compiler.getFunctionNames(bytecode);
|
|
311
|
+
if (Array.isArray(namesJson))
|
|
312
|
+
return namesJson;
|
|
313
|
+
return JSON.parse(namesJson);
|
|
314
|
+
}
|
|
315
|
+
catch (error) {
|
|
316
|
+
console.warn("[FiveSDK] Failed to extract function names:", error);
|
|
317
|
+
return [];
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
static async callFunctionByName(scriptAccount, functionName, parameters = [], accounts = [], connection, options = {}) {
|
|
321
|
+
const available = await this.getFunctionNamesFromScriptAccount(scriptAccount, connection);
|
|
322
|
+
if (!available) {
|
|
323
|
+
throw new Error(`Cannot resolve function name "${functionName}"`);
|
|
324
|
+
}
|
|
325
|
+
const funcInfo = available.find((f) => f.name === functionName);
|
|
326
|
+
if (!funcInfo) {
|
|
327
|
+
throw new Error(`Function "${functionName}" not found`);
|
|
328
|
+
}
|
|
329
|
+
return this.executeByIndex(scriptAccount, funcInfo.function_index, parameters, accounts, connection, options);
|
|
330
|
+
}
|
|
331
|
+
static async executeByIndex(scriptAccount, functionIndex, parameters = [], accounts = [], connection, options = {}) {
|
|
332
|
+
return this.generateExecuteInstruction(scriptAccount, functionIndex, parameters, accounts, connection, options);
|
|
333
|
+
}
|
|
334
|
+
static async getFunctionNamesFromScriptAccount(scriptAccount, connection) {
|
|
335
|
+
if (!connection)
|
|
336
|
+
return null;
|
|
337
|
+
try {
|
|
338
|
+
const { PublicKey } = await import("@solana/web3.js");
|
|
339
|
+
const accountInfo = await connection.getAccountInfo(new PublicKey(scriptAccount), "confirmed");
|
|
340
|
+
if (!accountInfo)
|
|
341
|
+
return null;
|
|
342
|
+
const data = accountInfo.data;
|
|
343
|
+
// Extract bytecode from account data.
|
|
344
|
+
const scriptHeaderSize = 64;
|
|
345
|
+
let bytecode = data;
|
|
346
|
+
if (data.length >= scriptHeaderSize && data[0] === 0x35 && data[1] === 0x49 && data[2] === 0x56 && data[3] === 0x45) {
|
|
347
|
+
const readU32LE = (buffer, offset) => buffer[offset] | (buffer[offset + 1] << 8) | (buffer[offset + 2] << 16) | (buffer[offset + 3] << 24);
|
|
348
|
+
const bytecodeLen = readU32LE(data, 48);
|
|
349
|
+
const metadataLen = readU32LE(data, 52);
|
|
350
|
+
const bytecodeStart = scriptHeaderSize + metadataLen;
|
|
351
|
+
if (bytecodeLen > 0 && (bytecodeStart + bytecodeLen) <= data.length) {
|
|
352
|
+
bytecode = data.slice(bytecodeStart, bytecodeStart + bytecodeLen);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
return await this.getFunctionNames(bytecode);
|
|
356
|
+
}
|
|
357
|
+
catch (e) {
|
|
358
|
+
return null;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
static async createDeploymentTransaction(bytecode, connection, deployerPublicKey, options = {}) {
|
|
362
|
+
return Deploy.createDeploymentTransaction(bytecode, connection, deployerPublicKey, options);
|
|
363
|
+
}
|
|
364
|
+
static async deployToSolana(bytecode, connection, deployerKeypair, options = {}) {
|
|
365
|
+
return Deploy.deployToSolana(bytecode, connection, deployerKeypair, options);
|
|
366
|
+
}
|
|
367
|
+
static async deployLargeProgramToSolana(bytecode, connection, deployerKeypair, options = {}) {
|
|
368
|
+
return Deploy.deployLargeProgramToSolana(bytecode, connection, deployerKeypair, options);
|
|
369
|
+
}
|
|
370
|
+
static async deployLargeProgramOptimizedToSolana(bytecode, connection, deployerKeypair, options = {}) {
|
|
371
|
+
return Deploy.deployLargeProgramOptimizedToSolana(bytecode, connection, deployerKeypair, options);
|
|
372
|
+
}
|
|
373
|
+
static async fetchAccountAndDeserialize(accountAddress, connection, options = {}) {
|
|
374
|
+
return Accounts.fetchAccountAndDeserialize(accountAddress, connection, options);
|
|
375
|
+
}
|
|
376
|
+
static async fetchMultipleAccountsAndDeserialize(accountAddresses, connection, options = {}) {
|
|
377
|
+
return Accounts.fetchMultipleAccountsAndDeserialize(accountAddresses, connection, options);
|
|
378
|
+
}
|
|
379
|
+
static async deserializeParameters(instructionData, expectedTypes = [], options = {}) {
|
|
380
|
+
return Accounts.deserializeParameters(instructionData, expectedTypes, options);
|
|
381
|
+
}
|
|
382
|
+
static async validateBytecodeEncoding(bytecode, debug = false) {
|
|
383
|
+
return Accounts.validateBytecodeEncoding(bytecode, debug);
|
|
384
|
+
}
|
|
385
|
+
static async executeWithStateDiff(scriptAccount, connection, signerKeypair, functionName, parameters = [], options = {}) {
|
|
386
|
+
return StateDiff.executeWithStateDiff(scriptAccount, connection, signerKeypair, functionName, parameters, options);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
FiveSDK.compiler = null;
|
|
390
|
+
FiveSDK.parameterEncoder = null;
|
|
391
|
+
FiveSDK.metadataCache = new MetadataCache();
|
|
392
|
+
// Export helper functions
|
|
393
|
+
export const createFiveSDK = (config) => new FiveSDK(config);
|
|
394
|
+
// Export default
|
|
395
|
+
export default FiveSDK;
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Five SDK Account System
|
|
3
|
+
*
|
|
4
|
+
* Client-agnostic account management system with validation, PDA derivation,
|
|
5
|
+
* and account size calculations. Uses serialization instead of direct blockchain calls.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Account data interface (replaces Web3.js AccountInfo)
|
|
9
|
+
*/
|
|
10
|
+
export interface AccountData {
|
|
11
|
+
/** Account address */
|
|
12
|
+
address: string;
|
|
13
|
+
/** Account data */
|
|
14
|
+
data: Uint8Array;
|
|
15
|
+
/** Account owner program ID */
|
|
16
|
+
owner: string;
|
|
17
|
+
/** Account balance in lamports */
|
|
18
|
+
lamports: number;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Account types in the Five VM ecosystem
|
|
22
|
+
*/
|
|
23
|
+
export type AccountType = 'script' | 'metadata' | 'user_state' | 'system' | 'rent_sysvar' | 'clock_sysvar' | 'spl_token' | 'custom';
|
|
24
|
+
/**
|
|
25
|
+
* AccountType enum for test compatibility
|
|
26
|
+
*/
|
|
27
|
+
export declare const AccountType: {
|
|
28
|
+
readonly SCRIPT: "script";
|
|
29
|
+
readonly METADATA: "metadata";
|
|
30
|
+
readonly USER_STATE: "user_state";
|
|
31
|
+
readonly SYSTEM: "system";
|
|
32
|
+
readonly RENT_SYSVAR: "rent_sysvar";
|
|
33
|
+
readonly CLOCK_SYSVAR: "clock_sysvar";
|
|
34
|
+
readonly SPL_TOKEN: "spl_token";
|
|
35
|
+
readonly CUSTOM: "custom";
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Account information with Five VM context
|
|
39
|
+
*/
|
|
40
|
+
export interface FiveAccount {
|
|
41
|
+
/** Account address */
|
|
42
|
+
address: string;
|
|
43
|
+
/** Account type */
|
|
44
|
+
type: AccountType;
|
|
45
|
+
/** Whether account is signer */
|
|
46
|
+
isSigner: boolean;
|
|
47
|
+
/** Whether account is writable */
|
|
48
|
+
isWritable: boolean;
|
|
49
|
+
/** Whether account is required for execution */
|
|
50
|
+
required?: boolean;
|
|
51
|
+
/** Account owner program ID */
|
|
52
|
+
owner?: string;
|
|
53
|
+
/** Account data size */
|
|
54
|
+
size?: number;
|
|
55
|
+
/** Account lamports balance */
|
|
56
|
+
lamports?: number;
|
|
57
|
+
/** Account data */
|
|
58
|
+
data?: Uint8Array;
|
|
59
|
+
/** PDA derivation info (if applicable) */
|
|
60
|
+
pda?: {
|
|
61
|
+
seeds: Uint8Array[];
|
|
62
|
+
bump: number;
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Account constraints for script execution
|
|
67
|
+
*/
|
|
68
|
+
export interface AccountConstraints {
|
|
69
|
+
/** Maximum number of accounts allowed */
|
|
70
|
+
maxAccounts?: number;
|
|
71
|
+
/** Maximum total size across all accounts */
|
|
72
|
+
maxTotalSize?: number;
|
|
73
|
+
/** Maximum rent cost allowed */
|
|
74
|
+
maxRentCost?: number;
|
|
75
|
+
/** Required account types that must be present */
|
|
76
|
+
requiredTypes?: AccountType[];
|
|
77
|
+
/** Required signers */
|
|
78
|
+
signers?: string[];
|
|
79
|
+
/** Required writable accounts */
|
|
80
|
+
writableAccounts?: string[];
|
|
81
|
+
/** Required readonly accounts */
|
|
82
|
+
readonlyAccounts?: string[];
|
|
83
|
+
/** Account type constraints */
|
|
84
|
+
typeConstraints?: Map<string, AccountType>;
|
|
85
|
+
/** Minimum rent exemption requirements */
|
|
86
|
+
rentRequirements?: Map<string, number>;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Account validation result
|
|
90
|
+
*/
|
|
91
|
+
export interface AccountValidationResult {
|
|
92
|
+
/** Whether validation passed */
|
|
93
|
+
valid: boolean;
|
|
94
|
+
/** Validation errors */
|
|
95
|
+
errors: string[];
|
|
96
|
+
/** Validation warnings */
|
|
97
|
+
warnings: string[];
|
|
98
|
+
/** Estimated costs */
|
|
99
|
+
costs?: {
|
|
100
|
+
rentExemption: number;
|
|
101
|
+
transactionFee: number;
|
|
102
|
+
totalCost: number;
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Account creation parameters
|
|
107
|
+
*/
|
|
108
|
+
export interface CreateAccountParams {
|
|
109
|
+
/** Account size in bytes */
|
|
110
|
+
size: number;
|
|
111
|
+
/** Owner program ID */
|
|
112
|
+
owner: string;
|
|
113
|
+
/** Whether to make rent-exempt */
|
|
114
|
+
rentExempt: boolean;
|
|
115
|
+
/** Additional lamports beyond rent exemption */
|
|
116
|
+
additionalLamports?: number;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Solana transaction instruction interface
|
|
120
|
+
*/
|
|
121
|
+
export interface TransactionInstruction {
|
|
122
|
+
/** Program ID to invoke */
|
|
123
|
+
programId: string;
|
|
124
|
+
/** Account keys and metadata */
|
|
125
|
+
accounts: Array<{
|
|
126
|
+
pubkey: string;
|
|
127
|
+
isSigner: boolean;
|
|
128
|
+
isWritable: boolean;
|
|
129
|
+
}>;
|
|
130
|
+
/** Instruction data */
|
|
131
|
+
data: Uint8Array;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Account manager for Five VM scripts (serialization-based)
|
|
135
|
+
*/
|
|
136
|
+
export declare class FiveAccountManager {
|
|
137
|
+
private programId;
|
|
138
|
+
constructor(programId?: string);
|
|
139
|
+
/**
|
|
140
|
+
* Encode System Program CreateAccount instruction
|
|
141
|
+
*/
|
|
142
|
+
private encodeCreateAccountInstruction;
|
|
143
|
+
/**
|
|
144
|
+
* Create script account PDA and return serialized instruction
|
|
145
|
+
*/
|
|
146
|
+
createScriptAccount(bytecode: Uint8Array, payerAddress: string): Promise<{
|
|
147
|
+
address: string;
|
|
148
|
+
bump: number;
|
|
149
|
+
createInstruction: TransactionInstruction;
|
|
150
|
+
rentLamports: number;
|
|
151
|
+
}>;
|
|
152
|
+
/**
|
|
153
|
+
* Create metadata account for script
|
|
154
|
+
*/
|
|
155
|
+
createMetadataAccount(scriptAccount: string, payerAddress: string): Promise<{
|
|
156
|
+
address: string;
|
|
157
|
+
bump: number;
|
|
158
|
+
createInstruction: TransactionInstruction;
|
|
159
|
+
rentLamports: number;
|
|
160
|
+
}>;
|
|
161
|
+
/**
|
|
162
|
+
* Create user state account for script interaction
|
|
163
|
+
*/
|
|
164
|
+
createUserStateAccount(userPublicKey: string, scriptAccount: string): Promise<{
|
|
165
|
+
address: string;
|
|
166
|
+
bump: number;
|
|
167
|
+
createInstruction: any;
|
|
168
|
+
rentLamports: number;
|
|
169
|
+
}>;
|
|
170
|
+
/**
|
|
171
|
+
* Validate account constraints for script execution
|
|
172
|
+
*/
|
|
173
|
+
validateAccountConstraints(accounts: FiveAccount[], constraints: AccountConstraints): Promise<AccountValidationResult>;
|
|
174
|
+
/**
|
|
175
|
+
* Get account info using client-agnostic account fetcher interface
|
|
176
|
+
*/
|
|
177
|
+
getAccountInfo(address: string, accountFetcher?: any): Promise<FiveAccount | null>;
|
|
178
|
+
/**
|
|
179
|
+
* Get multiple account infos in batch using client-agnostic interface
|
|
180
|
+
*/
|
|
181
|
+
getMultipleAccountInfos(addresses: string[], accountFetcher?: any): Promise<Map<string, FiveAccount | null>>;
|
|
182
|
+
/**
|
|
183
|
+
* Check if accounts exist and are properly initialized
|
|
184
|
+
*/
|
|
185
|
+
validateAccountsExist(addresses: string[]): Promise<{
|
|
186
|
+
existing: string[];
|
|
187
|
+
missing: string[];
|
|
188
|
+
invalid: string[];
|
|
189
|
+
}>;
|
|
190
|
+
/**
|
|
191
|
+
* Calculate total costs for account creation
|
|
192
|
+
*/
|
|
193
|
+
calculateAccountCreationCosts(accounts: Array<{
|
|
194
|
+
type: AccountType;
|
|
195
|
+
size: number;
|
|
196
|
+
}>): Promise<{
|
|
197
|
+
rentExemption: number;
|
|
198
|
+
transactionFees: number;
|
|
199
|
+
total: number;
|
|
200
|
+
breakdown: Array<{
|
|
201
|
+
type: AccountType;
|
|
202
|
+
size: number;
|
|
203
|
+
rent: number;
|
|
204
|
+
}>;
|
|
205
|
+
}>;
|
|
206
|
+
/**
|
|
207
|
+
* Build standard account list for script execution
|
|
208
|
+
*/
|
|
209
|
+
buildExecutionAccounts(scriptAccount: string, userAccount: string, additionalAccounts?: Array<{
|
|
210
|
+
address: string;
|
|
211
|
+
isSigner: boolean;
|
|
212
|
+
isWritable: boolean;
|
|
213
|
+
}>): FiveAccount[];
|
|
214
|
+
private determineAccountTypeFromData;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Account utilities for client-agnostic operations
|
|
218
|
+
*/
|
|
219
|
+
export declare class AccountUtils {
|
|
220
|
+
/**
|
|
221
|
+
* Build serializable account list (client-agnostic)
|
|
222
|
+
*/
|
|
223
|
+
static buildSerializableAccounts(accounts: FiveAccount[]): Array<{
|
|
224
|
+
pubkey: string;
|
|
225
|
+
isSigner: boolean;
|
|
226
|
+
isWritable: boolean;
|
|
227
|
+
}>;
|
|
228
|
+
/**
|
|
229
|
+
* Deduplicate account list while preserving most permissive permissions
|
|
230
|
+
*/
|
|
231
|
+
static deduplicateAccounts(accounts: FiveAccount[]): FiveAccount[];
|
|
232
|
+
/**
|
|
233
|
+
* Sort accounts by standard Solana conventions
|
|
234
|
+
*/
|
|
235
|
+
static sortAccounts(accounts: FiveAccount[]): FiveAccount[];
|
|
236
|
+
/**
|
|
237
|
+
* Validate account list structure and compute statistics
|
|
238
|
+
*/
|
|
239
|
+
static validateAccountList(accounts: FiveAccount[]): {
|
|
240
|
+
valid: boolean;
|
|
241
|
+
errors: string[];
|
|
242
|
+
totalSize: number;
|
|
243
|
+
requiredAccounts: FiveAccount[];
|
|
244
|
+
optionalAccounts: FiveAccount[];
|
|
245
|
+
};
|
|
246
|
+
/**
|
|
247
|
+
* Filter accounts by type
|
|
248
|
+
*/
|
|
249
|
+
static filterAccountsByType(accounts: FiveAccount[], type: AccountType): FiveAccount[];
|
|
250
|
+
/**
|
|
251
|
+
* Calculate total size of accounts
|
|
252
|
+
*/
|
|
253
|
+
static calculateTotalSize(accounts: FiveAccount[]): number;
|
|
254
|
+
}
|