@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
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
// Parameter encoding for Five VM.
|
|
2
|
+
import { ParameterEncodingError } from '../types.js';
|
|
3
|
+
// Type ID mapping (matches Five VM protocol).
|
|
4
|
+
const TYPE_IDS = {
|
|
5
|
+
'u8': 1,
|
|
6
|
+
'u16': 2,
|
|
7
|
+
'u32': 3,
|
|
8
|
+
'u64': 4,
|
|
9
|
+
'i8': 5,
|
|
10
|
+
'i16': 6,
|
|
11
|
+
'i32': 7,
|
|
12
|
+
'i64': 8,
|
|
13
|
+
'bool': 9,
|
|
14
|
+
'string': 11,
|
|
15
|
+
'pubkey': 10,
|
|
16
|
+
'bytes': 12,
|
|
17
|
+
'array': 13
|
|
18
|
+
};
|
|
19
|
+
export class ParameterEncoder {
|
|
20
|
+
constructor(debug = false) {
|
|
21
|
+
this.debug = debug;
|
|
22
|
+
if (this.debug) {
|
|
23
|
+
console.log('[ParameterEncoder] Initialized');
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
// ==================== Pure Parameter Encoding ====================
|
|
27
|
+
async encodeParameterData(parameters = [], functionSignature) {
|
|
28
|
+
if (this.debug) {
|
|
29
|
+
console.log(`[ParameterEncoder] Encoding parameter data: params=${parameters.length}`);
|
|
30
|
+
}
|
|
31
|
+
const encodedData = await this.encodeParametersInternal(parameters, functionSignature);
|
|
32
|
+
if (this.debug) {
|
|
33
|
+
console.log(`[ParameterEncoder] Encoded parameters: ${encodedData.length} bytes, hex: ${encodedData.toString('hex')}`);
|
|
34
|
+
}
|
|
35
|
+
return encodedData;
|
|
36
|
+
}
|
|
37
|
+
encodeParametersWithABI(parameters, functionSignature, options = {}) {
|
|
38
|
+
if (this.debug) {
|
|
39
|
+
console.log(`[ParameterEncoder] Encoding ${parameters.length} parameters with ABI guidance`);
|
|
40
|
+
}
|
|
41
|
+
const encoded = [];
|
|
42
|
+
for (let i = 0; i < parameters.length; i++) {
|
|
43
|
+
const value = parameters[i];
|
|
44
|
+
const paramDef = functionSignature.parameters[i];
|
|
45
|
+
if (!paramDef && options.strict) {
|
|
46
|
+
throw new ParameterEncodingError(`Parameter ${i} provided but function only expects ${functionSignature.parameters.length} parameters`, { functionName: functionSignature.name, parameterIndex: i });
|
|
47
|
+
}
|
|
48
|
+
// Use ABI type if available, otherwise infer
|
|
49
|
+
const targetType = paramDef?.type || this.inferType(value);
|
|
50
|
+
const encodedParam = this.encodeParameter(value, targetType, i);
|
|
51
|
+
encoded.push(encodedParam);
|
|
52
|
+
}
|
|
53
|
+
if (this.debug) {
|
|
54
|
+
console.log(`[ParameterEncoder] Encoded ${encoded.length} parameters successfully`);
|
|
55
|
+
}
|
|
56
|
+
return encoded;
|
|
57
|
+
}
|
|
58
|
+
// ==================== Type Coercion ====================
|
|
59
|
+
/// Coerce value to a Five VM type.
|
|
60
|
+
coerceValue(value, targetType) {
|
|
61
|
+
if (this.debug) {
|
|
62
|
+
console.log(`[ParameterEncoder] Coercing value ${JSON.stringify(value)} to ${targetType}`);
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
switch (targetType) {
|
|
66
|
+
case 'u8':
|
|
67
|
+
return this.coerceToU8(value);
|
|
68
|
+
case 'u16':
|
|
69
|
+
return this.coerceToU16(value);
|
|
70
|
+
case 'u32':
|
|
71
|
+
return this.coerceToU32(value);
|
|
72
|
+
case 'u64':
|
|
73
|
+
return this.coerceToU64(value);
|
|
74
|
+
case 'i8':
|
|
75
|
+
return this.coerceToI8(value);
|
|
76
|
+
case 'i16':
|
|
77
|
+
return this.coerceToI16(value);
|
|
78
|
+
case 'i32':
|
|
79
|
+
return this.coerceToI32(value);
|
|
80
|
+
case 'i64':
|
|
81
|
+
return this.coerceToI64(value);
|
|
82
|
+
case 'bool':
|
|
83
|
+
return this.coerceToBool(value);
|
|
84
|
+
case 'string':
|
|
85
|
+
return this.coerceToString(value);
|
|
86
|
+
case 'pubkey':
|
|
87
|
+
return this.coerceToPubkey(value);
|
|
88
|
+
case 'bytes':
|
|
89
|
+
return this.coerceToBytes(value);
|
|
90
|
+
case 'array':
|
|
91
|
+
return this.coerceToArray(value);
|
|
92
|
+
default:
|
|
93
|
+
throw new Error(`Unsupported type: ${targetType}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
throw new ParameterEncodingError(`Failed to coerce value ${JSON.stringify(value)} to ${targetType}: ${error instanceof Error ? error.message : 'Unknown error'}`, { value, targetType });
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// ==================== Private Methods ====================
|
|
101
|
+
/// Use BytecodeEncoder for parameter data only.
|
|
102
|
+
async encodeParametersInternal(parameters, functionSignature) {
|
|
103
|
+
try {
|
|
104
|
+
// Import BytecodeEncoder
|
|
105
|
+
const { BytecodeEncoder } = await import('../lib/bytecode-encoder.js');
|
|
106
|
+
// Convert parameters to format expected by encoder
|
|
107
|
+
const params = parameters.map((value, index) => {
|
|
108
|
+
const paramDef = functionSignature?.parameters[index];
|
|
109
|
+
return {
|
|
110
|
+
name: paramDef?.name || `param_${index}`,
|
|
111
|
+
type: paramDef?.type || this.inferTypeString(value)
|
|
112
|
+
};
|
|
113
|
+
});
|
|
114
|
+
const values = {};
|
|
115
|
+
params.forEach((param, index) => {
|
|
116
|
+
values[param.name] = parameters[index];
|
|
117
|
+
});
|
|
118
|
+
// Encode parameters only; function index is handled by the SDK when building instruction data
|
|
119
|
+
const encoded = await BytecodeEncoder.encodeExecute(0, params, values);
|
|
120
|
+
return Buffer.from(encoded);
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
throw new Error(`Parameter encoding failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/// Encode individual parameter.
|
|
127
|
+
encodeParameter(value, type, index) {
|
|
128
|
+
const coercedValue = this.coerceValue(value, type);
|
|
129
|
+
const typeId = TYPE_IDS[type];
|
|
130
|
+
return {
|
|
131
|
+
type: typeId,
|
|
132
|
+
value: coercedValue
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Infer Five VM type from JavaScript value
|
|
137
|
+
*/
|
|
138
|
+
inferType(value) {
|
|
139
|
+
if (typeof value === 'boolean') {
|
|
140
|
+
return 'bool';
|
|
141
|
+
}
|
|
142
|
+
if (typeof value === 'string') {
|
|
143
|
+
return 'string';
|
|
144
|
+
}
|
|
145
|
+
if (typeof value === 'number') {
|
|
146
|
+
// Default to u64 for positive integers, i64 for negative
|
|
147
|
+
return Number.isInteger(value) && value >= 0 ? 'u64' : 'i64';
|
|
148
|
+
}
|
|
149
|
+
if (typeof value === 'bigint') {
|
|
150
|
+
return value >= 0 ? 'u64' : 'i64';
|
|
151
|
+
}
|
|
152
|
+
if (Array.isArray(value)) {
|
|
153
|
+
return 'array';
|
|
154
|
+
}
|
|
155
|
+
return 'string'; // Default fallback
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Infer type as string
|
|
159
|
+
*/
|
|
160
|
+
inferTypeString(value) {
|
|
161
|
+
const type = this.inferType(value);
|
|
162
|
+
return type;
|
|
163
|
+
}
|
|
164
|
+
// ==================== Type Coercion Methods ====================
|
|
165
|
+
coerceToU8(value) {
|
|
166
|
+
const num = Number(value);
|
|
167
|
+
if (!Number.isInteger(num) || num < 0 || num > 255) {
|
|
168
|
+
throw new Error(`Value ${value} cannot be coerced to u8 (0-255)`);
|
|
169
|
+
}
|
|
170
|
+
return num;
|
|
171
|
+
}
|
|
172
|
+
coerceToU16(value) {
|
|
173
|
+
const num = Number(value);
|
|
174
|
+
if (!Number.isInteger(num) || num < 0 || num > 65535) {
|
|
175
|
+
throw new Error(`Value ${value} cannot be coerced to u16 (0-65535)`);
|
|
176
|
+
}
|
|
177
|
+
return num;
|
|
178
|
+
}
|
|
179
|
+
coerceToU32(value) {
|
|
180
|
+
const num = Number(value);
|
|
181
|
+
if (!Number.isInteger(num) || num < 0 || num > 4294967295) {
|
|
182
|
+
throw new Error(`Value ${value} cannot be coerced to u32 (0-4294967295)`);
|
|
183
|
+
}
|
|
184
|
+
return num;
|
|
185
|
+
}
|
|
186
|
+
coerceToU64(value) {
|
|
187
|
+
if (typeof value === 'bigint') {
|
|
188
|
+
if (value < BigInt(0) || value > BigInt('18446744073709551615')) {
|
|
189
|
+
throw new Error(`Value ${value} cannot be coerced to u64 (0-2^64-1)`);
|
|
190
|
+
}
|
|
191
|
+
return value;
|
|
192
|
+
}
|
|
193
|
+
const num = Number(value);
|
|
194
|
+
if (!Number.isInteger(num) || num < 0) {
|
|
195
|
+
throw new Error(`Value ${value} cannot be coerced to u64`);
|
|
196
|
+
}
|
|
197
|
+
return num;
|
|
198
|
+
}
|
|
199
|
+
coerceToI8(value) {
|
|
200
|
+
const num = Number(value);
|
|
201
|
+
if (!Number.isInteger(num) || num < -128 || num > 127) {
|
|
202
|
+
throw new Error(`Value ${value} cannot be coerced to i8 (-128 to 127)`);
|
|
203
|
+
}
|
|
204
|
+
return num;
|
|
205
|
+
}
|
|
206
|
+
coerceToI16(value) {
|
|
207
|
+
const num = Number(value);
|
|
208
|
+
if (!Number.isInteger(num) || num < -32768 || num > 32767) {
|
|
209
|
+
throw new Error(`Value ${value} cannot be coerced to i16 (-32768 to 32767)`);
|
|
210
|
+
}
|
|
211
|
+
return num;
|
|
212
|
+
}
|
|
213
|
+
coerceToI32(value) {
|
|
214
|
+
const num = Number(value);
|
|
215
|
+
if (!Number.isInteger(num) || num < -2147483648 || num > 2147483647) {
|
|
216
|
+
throw new Error(`Value ${value} cannot be coerced to i32 (-2^31 to 2^31-1)`);
|
|
217
|
+
}
|
|
218
|
+
return num;
|
|
219
|
+
}
|
|
220
|
+
coerceToI64(value) {
|
|
221
|
+
if (typeof value === 'bigint') {
|
|
222
|
+
if (value < BigInt('-9223372036854775808') || value > BigInt('9223372036854775807')) {
|
|
223
|
+
throw new Error(`Value ${value} cannot be coerced to i64 (-2^63 to 2^63-1)`);
|
|
224
|
+
}
|
|
225
|
+
return value;
|
|
226
|
+
}
|
|
227
|
+
const num = Number(value);
|
|
228
|
+
if (!Number.isInteger(num)) {
|
|
229
|
+
throw new Error(`Value ${value} cannot be coerced to i64`);
|
|
230
|
+
}
|
|
231
|
+
return num;
|
|
232
|
+
}
|
|
233
|
+
coerceToBool(value) {
|
|
234
|
+
if (typeof value === 'boolean') {
|
|
235
|
+
return value;
|
|
236
|
+
}
|
|
237
|
+
if (typeof value === 'string') {
|
|
238
|
+
const lower = value.toLowerCase();
|
|
239
|
+
if (lower === 'true' || lower === '1')
|
|
240
|
+
return true;
|
|
241
|
+
if (lower === 'false' || lower === '0')
|
|
242
|
+
return false;
|
|
243
|
+
throw new Error(`String "${value}" cannot be coerced to boolean`);
|
|
244
|
+
}
|
|
245
|
+
if (typeof value === 'number') {
|
|
246
|
+
return value !== 0;
|
|
247
|
+
}
|
|
248
|
+
throw new Error(`Value ${value} cannot be coerced to boolean`);
|
|
249
|
+
}
|
|
250
|
+
coerceToString(value) {
|
|
251
|
+
return String(value);
|
|
252
|
+
}
|
|
253
|
+
coerceToPubkey(value) {
|
|
254
|
+
if (typeof value === 'string' && value.length === 44) {
|
|
255
|
+
return value; // Assume base58 encoded pubkey
|
|
256
|
+
}
|
|
257
|
+
throw new Error(`Value ${value} cannot be coerced to pubkey`);
|
|
258
|
+
}
|
|
259
|
+
coerceToBytes(value) {
|
|
260
|
+
if (value instanceof Uint8Array) {
|
|
261
|
+
return value;
|
|
262
|
+
}
|
|
263
|
+
if (Array.isArray(value)) {
|
|
264
|
+
return new Uint8Array(value);
|
|
265
|
+
}
|
|
266
|
+
if (typeof value === 'string') {
|
|
267
|
+
// Assume hex string
|
|
268
|
+
return new Uint8Array(Buffer.from(value, 'hex'));
|
|
269
|
+
}
|
|
270
|
+
throw new Error(`Value ${value} cannot be coerced to bytes`);
|
|
271
|
+
}
|
|
272
|
+
coerceToArray(value) {
|
|
273
|
+
if (Array.isArray(value)) {
|
|
274
|
+
return value;
|
|
275
|
+
}
|
|
276
|
+
throw new Error(`Value ${value} cannot be coerced to array`);
|
|
277
|
+
}
|
|
278
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Five SDK - Client-Agnostic TypeScript/JavaScript library for Five VM
|
|
3
|
+
*
|
|
4
|
+
* Minimal build for Frontend integration.
|
|
5
|
+
*/
|
|
6
|
+
export * from './FiveSDK.js';
|
|
7
|
+
export * from './types.js';
|
|
8
|
+
export * from './lib/bytecode-encoder.js';
|
|
9
|
+
export * from './encoding/ParameterEncoder.js';
|
|
10
|
+
export * from './crypto/index.js';
|
|
11
|
+
export * from './project/toml.js';
|
|
12
|
+
export * from './project/config.js';
|
|
13
|
+
export * from './project/workspace.js';
|
|
14
|
+
export * from './wasm/vm.js';
|
|
15
|
+
export * from './wasm/compiler/index.js';
|
|
16
|
+
export * from './wasm/loader.js';
|
|
17
|
+
export * from './testing/index.js';
|
|
18
|
+
export * from './program/index.js';
|
|
19
|
+
export * from './modules/namespaces.js';
|
|
20
|
+
export { ProgramIdResolver, FIVE_BAKED_PROGRAM_ID } from './config/ProgramIdResolver.js';
|
|
21
|
+
export { FIVE_VM_PROGRAM_ID } from './types.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Five SDK - Client-Agnostic TypeScript/JavaScript library for Five VM
|
|
3
|
+
*
|
|
4
|
+
* Minimal build for Frontend integration.
|
|
5
|
+
*/
|
|
6
|
+
// ==================== Core SDK Exports ====================
|
|
7
|
+
export * from './FiveSDK.js';
|
|
8
|
+
export * from './types.js';
|
|
9
|
+
// export * from './validation/index.js'; // Might rely on broken things
|
|
10
|
+
export * from './lib/bytecode-encoder.js';
|
|
11
|
+
export * from './encoding/ParameterEncoder.js'; // Added missing export
|
|
12
|
+
export * from './crypto/index.js'; // Added missing export (for PDAUtils)
|
|
13
|
+
export * from './project/toml.js';
|
|
14
|
+
export * from './project/config.js';
|
|
15
|
+
export * from './project/workspace.js';
|
|
16
|
+
export * from './wasm/vm.js';
|
|
17
|
+
export * from './wasm/compiler/index.js';
|
|
18
|
+
export * from './wasm/loader.js';
|
|
19
|
+
export * from './testing/index.js';
|
|
20
|
+
// ==================== FiveProgram High-Level API ====================
|
|
21
|
+
export * from './program/index.js';
|
|
22
|
+
export * from './modules/namespaces.js';
|
|
23
|
+
// ==================== Program ID Resolution ====================
|
|
24
|
+
export { ProgramIdResolver, FIVE_BAKED_PROGRAM_ID } from './config/ProgramIdResolver.js';
|
|
25
|
+
// ==================== Constants ====================
|
|
26
|
+
export { FIVE_VM_PROGRAM_ID } from './types.js';
|
|
27
|
+
// Default export disabled for minimal build
|
|
28
|
+
// export { FiveSDK as default };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export interface ParameterDefinition {
|
|
2
|
+
name: string;
|
|
3
|
+
type: string;
|
|
4
|
+
isAccount?: boolean;
|
|
5
|
+
is_account?: boolean;
|
|
6
|
+
param_type?: string;
|
|
7
|
+
maxLen?: number;
|
|
8
|
+
}
|
|
9
|
+
export interface ParameterValue {
|
|
10
|
+
[key: string]: any;
|
|
11
|
+
}
|
|
12
|
+
export declare class BytecodeEncoder {
|
|
13
|
+
/**
|
|
14
|
+
* Parse a raw ABI type string into a canonical execute-encoding type.
|
|
15
|
+
* Supports sized string syntax like string<32>.
|
|
16
|
+
*/
|
|
17
|
+
static parseTypeSpec(rawType: string): {
|
|
18
|
+
baseType: string;
|
|
19
|
+
maxLen?: number;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Get type ID for encoding.
|
|
23
|
+
*/
|
|
24
|
+
static getTypeId(type: string): number;
|
|
25
|
+
/**
|
|
26
|
+
* Encode a 32-bit unsigned integer (Little Endian).
|
|
27
|
+
*/
|
|
28
|
+
static encodeU32(value: number): Uint8Array;
|
|
29
|
+
/**
|
|
30
|
+
* Encode execute instruction data using WASM ParameterEncoder.
|
|
31
|
+
*/
|
|
32
|
+
static encodeExecute(functionIndex: number, parameters?: ParameterDefinition[], values?: ParameterValue, retry?: boolean, options?: any): Promise<Buffer>;
|
|
33
|
+
private static isAccountParam;
|
|
34
|
+
private static getCanonicalTypeSpec;
|
|
35
|
+
private static normalizeType;
|
|
36
|
+
/**
|
|
37
|
+
* Parse parameter definitions from JSON string
|
|
38
|
+
*/
|
|
39
|
+
static parseParameters(parametersJson: string): {
|
|
40
|
+
definitions: ParameterDefinition[];
|
|
41
|
+
values: ParameterValue;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Validate WASM module availability
|
|
45
|
+
*/
|
|
46
|
+
static validateWasmModule(): Promise<{
|
|
47
|
+
available: boolean;
|
|
48
|
+
error?: string;
|
|
49
|
+
}>;
|
|
50
|
+
/**
|
|
51
|
+
* Create typed parameter definitions with validation
|
|
52
|
+
*/
|
|
53
|
+
static createTypedParameters(params: Array<{
|
|
54
|
+
name: string;
|
|
55
|
+
type: string;
|
|
56
|
+
value: any;
|
|
57
|
+
optional?: boolean;
|
|
58
|
+
}>): {
|
|
59
|
+
definitions: ParameterDefinition[];
|
|
60
|
+
values: ParameterValue;
|
|
61
|
+
};
|
|
62
|
+
}
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
// Bytecode encoder for the Five VM protocol.
|
|
2
|
+
import { getWasmModule } from '../wasm/loader.js';
|
|
3
|
+
let wasmModule = null;
|
|
4
|
+
// Type mapping for encoding - matches Five protocol types.
|
|
5
|
+
const TYPE_IDS = {
|
|
6
|
+
'u8': 1,
|
|
7
|
+
'u16': 2,
|
|
8
|
+
'u32': 3,
|
|
9
|
+
'u64': 4,
|
|
10
|
+
'i8': 5,
|
|
11
|
+
'i16': 6,
|
|
12
|
+
'i32': 7,
|
|
13
|
+
'i64': 8,
|
|
14
|
+
'bool': 9,
|
|
15
|
+
'pubkey': 10,
|
|
16
|
+
'string': 11,
|
|
17
|
+
'account': 12,
|
|
18
|
+
'bytes': 11,
|
|
19
|
+
'array': 13
|
|
20
|
+
};
|
|
21
|
+
export class BytecodeEncoder {
|
|
22
|
+
/**
|
|
23
|
+
* Parse a raw ABI type string into a canonical execute-encoding type.
|
|
24
|
+
* Supports sized string syntax like string<32>.
|
|
25
|
+
*/
|
|
26
|
+
static parseTypeSpec(rawType) {
|
|
27
|
+
const normalized = (rawType || '').toString().trim().toLowerCase();
|
|
28
|
+
const sizedStringMatch = normalized.match(/^string\s*<\s*(\d+)\s*>$/);
|
|
29
|
+
if (sizedStringMatch) {
|
|
30
|
+
return {
|
|
31
|
+
baseType: 'string',
|
|
32
|
+
maxLen: Number.parseInt(sizedStringMatch[1], 10),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
return { baseType: normalized };
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Get type ID for encoding.
|
|
39
|
+
*/
|
|
40
|
+
static getTypeId(type) {
|
|
41
|
+
const typeId = TYPE_IDS[type.toLowerCase()];
|
|
42
|
+
if (typeId === undefined) {
|
|
43
|
+
throw new Error(`Unknown type for encoding: ${type}`);
|
|
44
|
+
}
|
|
45
|
+
return typeId;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Encode a 32-bit unsigned integer (Little Endian).
|
|
49
|
+
*/
|
|
50
|
+
static encodeU32(value) {
|
|
51
|
+
const buffer = new Uint8Array(4);
|
|
52
|
+
buffer[0] = value & 0xff;
|
|
53
|
+
buffer[1] = (value >> 8) & 0xff;
|
|
54
|
+
buffer[2] = (value >> 16) & 0xff;
|
|
55
|
+
buffer[3] = (value >>> 24) & 0xff;
|
|
56
|
+
return buffer;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Encode execute instruction data using WASM ParameterEncoder.
|
|
60
|
+
*/
|
|
61
|
+
static async encodeExecute(functionIndex, parameters = [], values = {}, retry = true, options = {}) {
|
|
62
|
+
// Normalize parameter types before encoding to handle custom types (Mint, TokenAccount, etc.).
|
|
63
|
+
const normalizedParameters = parameters.map(p => {
|
|
64
|
+
const typeSpec = this.getCanonicalTypeSpec(p);
|
|
65
|
+
return {
|
|
66
|
+
...p,
|
|
67
|
+
type: typeSpec.baseType,
|
|
68
|
+
maxLen: typeSpec.maxLen,
|
|
69
|
+
};
|
|
70
|
+
});
|
|
71
|
+
// Load WASM module using shared loader
|
|
72
|
+
if (!wasmModule) {
|
|
73
|
+
try {
|
|
74
|
+
wasmModule = await getWasmModule();
|
|
75
|
+
// Check if loaded module is valid.
|
|
76
|
+
if (wasmModule && wasmModule.ParameterEncoder) {
|
|
77
|
+
try {
|
|
78
|
+
// Health check: try to encode empty params.
|
|
79
|
+
wasmModule.ParameterEncoder.encode_execute(0, []);
|
|
80
|
+
}
|
|
81
|
+
catch (e) {
|
|
82
|
+
console.warn("[BytecodeEncoder] Module validation failed, falling back:", e.message);
|
|
83
|
+
wasmModule = null; // Force retry with inline loader
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
wasmModule = null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
catch (e) {
|
|
91
|
+
// Silently ignore loader errors and try fallback
|
|
92
|
+
wasmModule = null;
|
|
93
|
+
}
|
|
94
|
+
// Fallback: import the wasm-pack generated module for Node.js.
|
|
95
|
+
if (!wasmModule && typeof process !== 'undefined') {
|
|
96
|
+
console.log("[DEBUG] (SRC) Attempting wasm-pack module import...");
|
|
97
|
+
try {
|
|
98
|
+
const fs = await import('fs');
|
|
99
|
+
const path = await import('path');
|
|
100
|
+
const url = await import('url');
|
|
101
|
+
const __dirname = path.dirname(url.fileURLToPath(import.meta.url));
|
|
102
|
+
// Import the wasm-pack generated entry point (five_vm_wasm.js)
|
|
103
|
+
// which already handles all the WASM initialization.
|
|
104
|
+
const moduleEntryPath = path.resolve(__dirname, '../assets/vm/five_vm_wasm.js');
|
|
105
|
+
if (fs.existsSync(moduleEntryPath)) {
|
|
106
|
+
console.log("[DEBUG] Found WASM module at:", moduleEntryPath);
|
|
107
|
+
const wasmMod = await import(moduleEntryPath);
|
|
108
|
+
// The wasm-pack module exports the initialized module directly.
|
|
109
|
+
if (wasmMod && wasmMod.ParameterEncoder) {
|
|
110
|
+
wasmModule = wasmMod;
|
|
111
|
+
console.log("[DEBUG] WASM module imported and initialized successfully!");
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
console.error("[DEBUG] WASM module missing expected exports");
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
console.error("[DEBUG] WASM module not found at:", moduleEntryPath);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
console.error("[DEBUG] Module import FAILED:", err);
|
|
123
|
+
// Don't throw - let it fall through to error handling below.
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
const filteredParams = normalizedParameters;
|
|
128
|
+
const paramValues = filteredParams.map(param => {
|
|
129
|
+
const value = values[param.name];
|
|
130
|
+
if (value === undefined || value === null) {
|
|
131
|
+
throw new Error(`Missing value for parameter: ${param.name}`);
|
|
132
|
+
}
|
|
133
|
+
return { param, value };
|
|
134
|
+
});
|
|
135
|
+
if (options && options.debug) {
|
|
136
|
+
console.log(`[BytecodeEncoder] Parameters:`, paramValues.map(p => ({
|
|
137
|
+
name: p.param.name,
|
|
138
|
+
type: p.param.type || p.param.param_type,
|
|
139
|
+
normalized: this.getCanonicalTypeSpec(p.param).baseType,
|
|
140
|
+
maxLen: this.getCanonicalTypeSpec(p.param).maxLen,
|
|
141
|
+
isAccount: this.isAccountParam(p.param)
|
|
142
|
+
})));
|
|
143
|
+
}
|
|
144
|
+
// Build parameter array with full metadata for fixed-size WASM encoder
|
|
145
|
+
const paramArray = paramValues.map(({ param, value }) => {
|
|
146
|
+
const canonicalType = this.getCanonicalTypeSpec(param);
|
|
147
|
+
// Pass full parameter definition for type-aware encoding
|
|
148
|
+
return {
|
|
149
|
+
name: param.name,
|
|
150
|
+
type: canonicalType.baseType,
|
|
151
|
+
param_type: canonicalType.baseType,
|
|
152
|
+
maxLen: canonicalType.maxLen,
|
|
153
|
+
isAccount: canonicalType.baseType === 'account',
|
|
154
|
+
is_account: canonicalType.baseType === 'account',
|
|
155
|
+
value: value
|
|
156
|
+
};
|
|
157
|
+
});
|
|
158
|
+
try {
|
|
159
|
+
// Debug logging to understand parameter encoding
|
|
160
|
+
console.log(`[BytecodeEncoder] About to encode with paramArray:`, JSON.stringify(paramArray.map(p => ({
|
|
161
|
+
name: p.name || 'unknown',
|
|
162
|
+
type: p.type || 'unknown',
|
|
163
|
+
hasValue: p.value !== undefined
|
|
164
|
+
}))));
|
|
165
|
+
const encoded = wasmModule.ParameterEncoder.encode_execute(functionIndex, paramArray);
|
|
166
|
+
if (options && options.debug) {
|
|
167
|
+
const buf = Buffer.from(encoded);
|
|
168
|
+
console.log(`[BytecodeEncoder] WASM encoded ${paramArray.length} parameters: ${buf.length} bytes`);
|
|
169
|
+
}
|
|
170
|
+
console.log(`[BytecodeEncoder] Encoded result: ${Buffer.from(encoded).toString('hex')}`);
|
|
171
|
+
return Buffer.from(encoded);
|
|
172
|
+
}
|
|
173
|
+
catch (e) {
|
|
174
|
+
console.warn("[BytecodeEncoder] Encode failed via WASM:", e);
|
|
175
|
+
if (retry) {
|
|
176
|
+
console.warn("[BytecodeEncoder] Reloading WASM module and retrying...");
|
|
177
|
+
wasmModule = null; // Force reload.
|
|
178
|
+
return this.encodeExecute(functionIndex, parameters, values, false, options);
|
|
179
|
+
}
|
|
180
|
+
throw e;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
static isAccountParam(param) {
|
|
184
|
+
if (param.isAccount || param.is_account) {
|
|
185
|
+
return true;
|
|
186
|
+
}
|
|
187
|
+
const type = this.getCanonicalTypeSpec(param).baseType;
|
|
188
|
+
return type === 'account';
|
|
189
|
+
}
|
|
190
|
+
static getCanonicalTypeSpec(param) {
|
|
191
|
+
if (param.isAccount || param.is_account) {
|
|
192
|
+
return { baseType: 'account' };
|
|
193
|
+
}
|
|
194
|
+
const rawType = (param.type || param.param_type || '').toString().trim();
|
|
195
|
+
const parsed = this.parseTypeSpec(rawType);
|
|
196
|
+
const explicitMaxLen = param.maxLen;
|
|
197
|
+
if (parsed.baseType === 'string' &&
|
|
198
|
+
explicitMaxLen !== undefined &&
|
|
199
|
+
explicitMaxLen !== null) {
|
|
200
|
+
const maxLen = Number.parseInt(String(explicitMaxLen), 10);
|
|
201
|
+
if (!Number.isNaN(maxLen)) {
|
|
202
|
+
return { baseType: 'string', maxLen };
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
// Special handling for common account-backed types in the DSL
|
|
206
|
+
if (['mint', 'tokenaccount'].includes(parsed.baseType)) {
|
|
207
|
+
return { baseType: 'account' };
|
|
208
|
+
}
|
|
209
|
+
return parsed;
|
|
210
|
+
}
|
|
211
|
+
static normalizeType(param) {
|
|
212
|
+
return this.getCanonicalTypeSpec(param).baseType;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Parse parameter definitions from JSON string
|
|
216
|
+
*/
|
|
217
|
+
static parseParameters(parametersJson) {
|
|
218
|
+
try {
|
|
219
|
+
const parsed = JSON.parse(parametersJson);
|
|
220
|
+
if (Array.isArray(parsed)) {
|
|
221
|
+
// Array format: [{ name: "a", type: "u64", value: 123 }, ...]
|
|
222
|
+
const definitions = [];
|
|
223
|
+
const values = {};
|
|
224
|
+
for (const param of parsed) {
|
|
225
|
+
if (!param.name || !param.type || param.value === undefined) {
|
|
226
|
+
throw new Error('Parameter must have name, type, and value fields');
|
|
227
|
+
}
|
|
228
|
+
definitions.push({ name: param.name, type: param.type });
|
|
229
|
+
values[param.name] = param.value;
|
|
230
|
+
}
|
|
231
|
+
return { definitions, values };
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
throw new Error('Object format parameters require type definitions. Use array format: [{ name: "a", type: "u64", value: 123 }]');
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
catch (error) {
|
|
238
|
+
throw new Error(`Invalid parameters JSON: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Validate WASM module availability
|
|
243
|
+
*/
|
|
244
|
+
static async validateWasmModule() {
|
|
245
|
+
try {
|
|
246
|
+
if (!wasmModule) {
|
|
247
|
+
wasmModule = await getWasmModule();
|
|
248
|
+
}
|
|
249
|
+
if (!wasmModule.ParameterEncoder) {
|
|
250
|
+
return { available: false, error: 'ParameterEncoder not found in WASM module' };
|
|
251
|
+
}
|
|
252
|
+
return { available: true };
|
|
253
|
+
}
|
|
254
|
+
catch (error) {
|
|
255
|
+
return {
|
|
256
|
+
available: false,
|
|
257
|
+
error: `WASM module not available: ${error instanceof Error ? error.message : 'Unknown error'}`
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Create typed parameter definitions with validation
|
|
263
|
+
*/
|
|
264
|
+
static createTypedParameters(params) {
|
|
265
|
+
const definitions = [];
|
|
266
|
+
const values = {};
|
|
267
|
+
for (const param of params) {
|
|
268
|
+
if (!TYPE_IDS[param.type.toLowerCase()]) {
|
|
269
|
+
throw new Error(`Unknown parameter type: ${param.type}`);
|
|
270
|
+
}
|
|
271
|
+
if (!param.optional && (param.value === undefined || param.value === null)) {
|
|
272
|
+
throw new Error(`Missing value for required parameter: ${param.name}`);
|
|
273
|
+
}
|
|
274
|
+
definitions.push({ name: param.name, type: param.type });
|
|
275
|
+
if (param.value !== undefined) {
|
|
276
|
+
values[param.name] = param.value;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
return { definitions, values };
|
|
280
|
+
}
|
|
281
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple logging that can be silenced in production
|
|
3
|
+
*/
|
|
4
|
+
export declare const log: {
|
|
5
|
+
debug: (message: string, ...args: any[]) => void;
|
|
6
|
+
info: (message: string, ...args: any[]) => void;
|
|
7
|
+
warn: (message: string, ...args: any[]) => void;
|
|
8
|
+
error: (message: string, ...args: any[]) => void;
|
|
9
|
+
};
|