@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.
Files changed (119) hide show
  1. package/README.md +279 -0
  2. package/dist/FiveSDK.d.ts +336 -0
  3. package/dist/FiveSDK.js +395 -0
  4. package/dist/accounts/index.d.ts +254 -0
  5. package/dist/accounts/index.js +543 -0
  6. package/dist/assets/vm/dummy.file +0 -0
  7. package/dist/assets/vm/five_vm_wasm.d.ts +762 -0
  8. package/dist/assets/vm/five_vm_wasm.js +3754 -0
  9. package/dist/assets/vm/five_vm_wasm_bg.js +3307 -0
  10. package/dist/assets/vm/five_vm_wasm_bg.wasm +0 -0
  11. package/dist/assets/vm/five_vm_wasm_bg.wasm.d.ts +247 -0
  12. package/dist/assets/vm/package.json +11 -0
  13. package/dist/bin/gen-types.d.ts +2 -0
  14. package/dist/bin/gen-types.js +35 -0
  15. package/dist/compiler/BytecodeCompiler.d.ts +83 -0
  16. package/dist/compiler/BytecodeCompiler.js +379 -0
  17. package/dist/config/ConfigManager.d.ts +13 -0
  18. package/dist/config/ConfigManager.js +27 -0
  19. package/dist/config/ProgramIdResolver.d.ts +62 -0
  20. package/dist/config/ProgramIdResolver.js +104 -0
  21. package/dist/crypto/index.d.ts +211 -0
  22. package/dist/crypto/index.js +451 -0
  23. package/dist/encoding/ParameterEncoder.d.ts +31 -0
  24. package/dist/encoding/ParameterEncoder.js +278 -0
  25. package/dist/index.d.ts +21 -0
  26. package/dist/index.js +28 -0
  27. package/dist/lib/bytecode-encoder.d.ts +62 -0
  28. package/dist/lib/bytecode-encoder.js +281 -0
  29. package/dist/logging/index.d.ts +9 -0
  30. package/dist/logging/index.js +10 -0
  31. package/dist/metadata/index.d.ts +213 -0
  32. package/dist/metadata/index.js +296 -0
  33. package/dist/modules/accounts.d.ts +60 -0
  34. package/dist/modules/accounts.js +275 -0
  35. package/dist/modules/deploy.d.ts +90 -0
  36. package/dist/modules/deploy.js +1118 -0
  37. package/dist/modules/execute.d.ts +90 -0
  38. package/dist/modules/execute.js +649 -0
  39. package/dist/modules/fees.d.ts +14 -0
  40. package/dist/modules/fees.js +112 -0
  41. package/dist/modules/namespaces.d.ts +39 -0
  42. package/dist/modules/namespaces.js +190 -0
  43. package/dist/modules/state-diff.d.ts +35 -0
  44. package/dist/modules/state-diff.js +342 -0
  45. package/dist/modules/vm-state.d.ts +7 -0
  46. package/dist/modules/vm-state.js +44 -0
  47. package/dist/program/AccountResolver.d.ts +67 -0
  48. package/dist/program/AccountResolver.js +134 -0
  49. package/dist/program/BorshSchemaGenerator.d.ts +8 -0
  50. package/dist/program/BorshSchemaGenerator.js +57 -0
  51. package/dist/program/FiveProgram.d.ts +144 -0
  52. package/dist/program/FiveProgram.js +282 -0
  53. package/dist/program/FunctionBuilder.d.ts +114 -0
  54. package/dist/program/FunctionBuilder.js +347 -0
  55. package/dist/program/ProgramAccount.d.ts +38 -0
  56. package/dist/program/ProgramAccount.js +170 -0
  57. package/dist/program/TypeGenerator.d.ts +90 -0
  58. package/dist/program/TypeGenerator.js +195 -0
  59. package/dist/program/index.d.ts +24 -0
  60. package/dist/program/index.js +21 -0
  61. package/dist/project/config.d.ts +5 -0
  62. package/dist/project/config.js +33 -0
  63. package/dist/project/toml.d.ts +6 -0
  64. package/dist/project/toml.js +43 -0
  65. package/dist/project/workspace.d.ts +160 -0
  66. package/dist/project/workspace.js +73 -0
  67. package/dist/testing/AccountMetaGenerator.d.ts +121 -0
  68. package/dist/testing/AccountMetaGenerator.js +261 -0
  69. package/dist/testing/AccountTestFixture.d.ts +211 -0
  70. package/dist/testing/AccountTestFixture.js +530 -0
  71. package/dist/testing/OnChainAccountManager.d.ts +81 -0
  72. package/dist/testing/OnChainAccountManager.js +260 -0
  73. package/dist/testing/StateSerializer.d.ts +65 -0
  74. package/dist/testing/StateSerializer.js +330 -0
  75. package/dist/testing/TestDiscovery.d.ts +79 -0
  76. package/dist/testing/TestDiscovery.js +274 -0
  77. package/dist/testing/TestRunner.d.ts +117 -0
  78. package/dist/testing/TestRunner.js +346 -0
  79. package/dist/testing/index.d.ts +14 -0
  80. package/dist/testing/index.js +13 -0
  81. package/dist/types.d.ts +356 -0
  82. package/dist/types.js +32 -0
  83. package/dist/utils/abi.d.ts +31 -0
  84. package/dist/utils/abi.js +92 -0
  85. package/dist/utils/transaction.d.ts +5 -0
  86. package/dist/utils/transaction.js +48 -0
  87. package/dist/validation/InputValidator.d.ts +142 -0
  88. package/dist/validation/InputValidator.js +332 -0
  89. package/dist/validation/index.d.ts +4 -0
  90. package/dist/validation/index.js +4 -0
  91. package/dist/wasm/compiler/AbiLogic.d.ts +4 -0
  92. package/dist/wasm/compiler/AbiLogic.js +37 -0
  93. package/dist/wasm/compiler/AnalysisLogic.d.ts +6 -0
  94. package/dist/wasm/compiler/AnalysisLogic.js +61 -0
  95. package/dist/wasm/compiler/CompilationLogic.d.ts +10 -0
  96. package/dist/wasm/compiler/CompilationLogic.js +431 -0
  97. package/dist/wasm/compiler/FiveCompiler.d.ts +48 -0
  98. package/dist/wasm/compiler/FiveCompiler.js +183 -0
  99. package/dist/wasm/compiler/InfoLogic.d.ts +6 -0
  100. package/dist/wasm/compiler/InfoLogic.js +24 -0
  101. package/dist/wasm/compiler/OptimizationLogic.d.ts +2 -0
  102. package/dist/wasm/compiler/OptimizationLogic.js +13 -0
  103. package/dist/wasm/compiler/ValidationLogic.d.ts +7 -0
  104. package/dist/wasm/compiler/ValidationLogic.js +26 -0
  105. package/dist/wasm/compiler/index.d.ts +2 -0
  106. package/dist/wasm/compiler/index.js +2 -0
  107. package/dist/wasm/compiler/types.d.ts +8 -0
  108. package/dist/wasm/compiler/types.js +1 -0
  109. package/dist/wasm/compiler/utils.d.ts +8 -0
  110. package/dist/wasm/compiler/utils.js +75 -0
  111. package/dist/wasm/index.d.ts +9 -0
  112. package/dist/wasm/index.js +12 -0
  113. package/dist/wasm/instance.d.ts +1 -0
  114. package/dist/wasm/instance.js +26 -0
  115. package/dist/wasm/loader.d.ts +7 -0
  116. package/dist/wasm/loader.js +112 -0
  117. package/dist/wasm/vm.d.ts +33 -0
  118. package/dist/wasm/vm.js +250 -0
  119. package/package.json +59 -0
@@ -0,0 +1,260 @@
1
+ /**
2
+ * On-Chain Account Manager for Five VM Account-System Testing
3
+ *
4
+ * Creates and manages real Solana accounts on-chain for comprehensive account-system testing.
5
+ * Handles account creation, funding, initialization, and cleanup.
6
+ */
7
+ import { Keypair, PublicKey, SystemProgram, Transaction, sendAndConfirmTransaction, LAMPORTS_PER_SOL } from '@solana/web3.js';
8
+ import { RentCalculator } from '../crypto/index.js';
9
+ import { PDAUtils } from '../crypto/index.js';
10
+ /**
11
+ * Manages creation and lifecycle of real Solana accounts for testing
12
+ */
13
+ export class OnChainAccountManager {
14
+ constructor(connection, payer, options = {}) {
15
+ this.connection = connection;
16
+ this.payer = payer;
17
+ this.options = options;
18
+ this.createdAccounts = [];
19
+ this.signers = new Map();
20
+ this.options.maxRetries = this.options.maxRetries || 3;
21
+ this.options.retryDelay = this.options.retryDelay || 1000;
22
+ }
23
+ /**
24
+ * Create a signer account with generated keypair
25
+ * Transfers SOL from payer to fund the account
26
+ */
27
+ async createSignerAccount(lamports = LAMPORTS_PER_SOL // 1 SOL default
28
+ ) {
29
+ const keypair = Keypair.generate();
30
+ const publicKey = keypair.publicKey;
31
+ if (this.options.debug) {
32
+ console.log(`[OnChainAccountManager] Creating signer account: ${publicKey.toString()}`);
33
+ }
34
+ // Ensure payer has sufficient balance
35
+ await this.ensureSufficientBalance(lamports);
36
+ // Transfer SOL from payer to new account
37
+ const transaction = new Transaction().add(SystemProgram.transfer({
38
+ fromPubkey: this.payer.publicKey,
39
+ toPubkey: publicKey,
40
+ lamports: lamports,
41
+ }));
42
+ try {
43
+ const signature = await sendAndConfirmTransaction(this.connection, transaction, [this.payer], { commitment: 'confirmed' });
44
+ if (this.options.debug) {
45
+ console.log(`[OnChainAccountManager] Signer account funded: ${signature}`);
46
+ }
47
+ this.createdAccounts.push(publicKey);
48
+ this.signers.set(publicKey.toString(), keypair);
49
+ return { publicKey, keypair };
50
+ }
51
+ catch (error) {
52
+ const errorMessage = error instanceof Error ? error.message : String(error);
53
+ throw new Error(`Failed to create signer account: ${errorMessage}`);
54
+ }
55
+ }
56
+ /**
57
+ * Create a regular account with specified space and owner
58
+ * Uses SystemProgram.createAccount for account creation
59
+ */
60
+ async createAccount(space, owner, lamports) {
61
+ const keypair = Keypair.generate();
62
+ const publicKey = keypair.publicKey;
63
+ // Calculate rent-exempt lamports if not provided
64
+ const requiredLamports = lamports || RentCalculator.calculateRentExemption(space);
65
+ if (this.options.debug) {
66
+ console.log(`[OnChainAccountManager] Creating account: ${publicKey.toString()} ` +
67
+ `(space=${space}, lamports=${requiredLamports})`);
68
+ }
69
+ // Ensure payer has sufficient balance
70
+ await this.ensureSufficientBalance(requiredLamports);
71
+ // Create the account using SystemProgram
72
+ const transaction = new Transaction().add(SystemProgram.createAccount({
73
+ fromPubkey: this.payer.publicKey,
74
+ newAccountPubkey: publicKey,
75
+ lamports: requiredLamports,
76
+ space: space,
77
+ programId: owner,
78
+ }));
79
+ try {
80
+ const signature = await sendAndConfirmTransaction(this.connection, transaction, [this.payer, keypair], { commitment: 'confirmed' });
81
+ if (this.options.debug) {
82
+ console.log(`[OnChainAccountManager] Account created: ${signature}`);
83
+ }
84
+ this.createdAccounts.push(publicKey);
85
+ return publicKey;
86
+ }
87
+ catch (error) {
88
+ const errorMessage = error instanceof Error ? error.message : String(error);
89
+ throw new Error(`Failed to create account: ${errorMessage}`);
90
+ }
91
+ }
92
+ /**
93
+ * Create and initialize a state account with initial data
94
+ */
95
+ async createStateAccount(space, owner, initialData, lamports) {
96
+ const accountAddress = await this.createAccount(space, owner, lamports);
97
+ // Write initial data if provided
98
+ if (initialData && initialData.length > 0) {
99
+ await this.writeAccountData(accountAddress, initialData);
100
+ }
101
+ if (this.options.debug) {
102
+ console.log(`[OnChainAccountManager] State account initialized: ${accountAddress.toString()}`);
103
+ }
104
+ return accountAddress;
105
+ }
106
+ /**
107
+ * Create a PDA account at a specific seed path
108
+ */
109
+ async createPDAAccount(seeds, programId, space, owner, lamports) {
110
+ const pda = await PDAUtils.findProgramAddress(seeds, programId.toString());
111
+ const pdaAddress = new PublicKey(pda.address);
112
+ if (this.options.debug) {
113
+ console.log(`[OnChainAccountManager] Creating PDA: ${pdaAddress.toString()} ` +
114
+ `(bump=${pda.bump})`);
115
+ }
116
+ // Check if PDA already exists
117
+ const exists = await this.checkAccountExists(pdaAddress);
118
+ if (exists) {
119
+ if (this.options.debug) {
120
+ console.log(`[OnChainAccountManager] PDA already exists, skipping creation`);
121
+ }
122
+ return { publicKey: pdaAddress, bump: pda.bump };
123
+ }
124
+ // Create PDA account
125
+ const createdAddress = await this.createAccount(space, owner || programId, lamports);
126
+ return { publicKey: createdAddress, bump: pda.bump };
127
+ }
128
+ /**
129
+ * Write data to an account (requires account to be writable)
130
+ */
131
+ async writeAccountData(accountAddress, data) {
132
+ if (this.options.debug) {
133
+ console.log(`[OnChainAccountManager] Writing ${data.length} bytes to account: ${accountAddress.toString()}`);
134
+ }
135
+ // Note: Writing data directly to an account requires special instructions
136
+ // This is a simplified implementation. In practice, you would use the Five VM program
137
+ // or SystemProgram.allocate + loader to write data.
138
+ // Log that data would be written.
139
+ if (this.options.debug) {
140
+ console.log(`[OnChainAccountManager] Data would be written via Five VM program`);
141
+ }
142
+ }
143
+ /**
144
+ * Check if an account exists
145
+ */
146
+ async checkAccountExists(publicKey) {
147
+ try {
148
+ const accountInfo = await this.connection.getAccountInfo(publicKey);
149
+ return accountInfo !== null;
150
+ }
151
+ catch (error) {
152
+ if (this.options.debug) {
153
+ const errorMessage = error instanceof Error ? error.message : String(error);
154
+ console.log(`[OnChainAccountManager] Error checking account: ${errorMessage}`);
155
+ }
156
+ return false;
157
+ }
158
+ }
159
+ /**
160
+ * Ensure payer has sufficient balance
161
+ */
162
+ async ensureSufficientBalance(required) {
163
+ const balance = await this.connection.getBalance(this.payer.publicKey);
164
+ // Add buffer for transaction fees (0.01 SOL)
165
+ const feeBuffer = 0.01 * LAMPORTS_PER_SOL;
166
+ const totalRequired = required + feeBuffer;
167
+ if (balance < totalRequired) {
168
+ throw new Error(`Insufficient balance: ${(balance / LAMPORTS_PER_SOL).toFixed(4)} SOL available, ` +
169
+ `${(totalRequired / LAMPORTS_PER_SOL).toFixed(4)} SOL required. ` +
170
+ `Please fund the payer account: ${this.payer.publicKey.toString()}`);
171
+ }
172
+ }
173
+ /**
174
+ * Create account with retry logic
175
+ */
176
+ async createAccountWithRetry(createFn, options = {}) {
177
+ const maxRetries = options.maxRetries || this.options.maxRetries || 3;
178
+ const retryDelay = options.retryDelay || this.options.retryDelay || 1000;
179
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
180
+ try {
181
+ return await createFn();
182
+ }
183
+ catch (error) {
184
+ const errorMessage = error instanceof Error ? error.message : String(error);
185
+ if (attempt === maxRetries) {
186
+ throw new Error(`Failed to create account after ${maxRetries} attempts: ${errorMessage}`);
187
+ }
188
+ if (this.options.debug) {
189
+ console.log(`[OnChainAccountManager] Account creation failed (attempt ${attempt}/${maxRetries}), ` +
190
+ `retrying in ${retryDelay}ms...`);
191
+ }
192
+ await new Promise(resolve => setTimeout(resolve, retryDelay));
193
+ }
194
+ }
195
+ throw new Error('Unreachable');
196
+ }
197
+ /**
198
+ * Get a signer keypair if it was created by this manager
199
+ */
200
+ getSignerKeypair(publicKey) {
201
+ const key = typeof publicKey === 'string' ? publicKey : publicKey.toString();
202
+ return this.signers.get(key);
203
+ }
204
+ /**
205
+ * Get all created accounts
206
+ */
207
+ getCreatedAccounts() {
208
+ return [...this.createdAccounts];
209
+ }
210
+ /**
211
+ * Cleanup: Close all created accounts and transfer remaining SOL back to payer
212
+ * This helps with test isolation and prevents account accumulation on testnet
213
+ */
214
+ async cleanup() {
215
+ if (!this.options.cleanup) {
216
+ if (this.options.debug) {
217
+ console.log(`[OnChainAccountManager] Cleanup disabled, skipping`);
218
+ }
219
+ return;
220
+ }
221
+ if (this.options.debug) {
222
+ console.log(`[OnChainAccountManager] Cleaning up ${this.createdAccounts.length} accounts`);
223
+ }
224
+ // Close accounts and transfer lamports back to payer
225
+ for (const accountAddress of this.createdAccounts) {
226
+ try {
227
+ // Get account info to determine if it's an account we can close
228
+ const accountInfo = await this.connection.getAccountInfo(accountAddress);
229
+ if (accountInfo) {
230
+ // Only try to close accounts owned by SystemProgram (data accounts)
231
+ // Don't try to close program accounts or special accounts
232
+ if (accountInfo.owner.equals(SystemProgram.programId)) {
233
+ const transaction = new Transaction().add(SystemProgram.transfer({
234
+ fromPubkey: accountAddress,
235
+ toPubkey: this.payer.publicKey,
236
+ lamports: accountInfo.lamports,
237
+ }));
238
+ const signer = this.getSignerKeypair(accountAddress);
239
+ if (signer) {
240
+ await sendAndConfirmTransaction(this.connection, transaction, [signer], { commitment: 'confirmed' });
241
+ if (this.options.debug) {
242
+ console.log(`[OnChainAccountManager] Closed account: ${accountAddress.toString()}`);
243
+ }
244
+ }
245
+ }
246
+ }
247
+ }
248
+ catch (error) {
249
+ const errorMessage = error instanceof Error ? error.message : String(error);
250
+ if (this.options.debug) {
251
+ console.log(`[OnChainAccountManager] Error closing account ${accountAddress.toString()}: ` +
252
+ `${errorMessage}`);
253
+ }
254
+ }
255
+ }
256
+ this.createdAccounts = [];
257
+ this.signers.clear();
258
+ }
259
+ }
260
+ export default OnChainAccountManager;
@@ -0,0 +1,65 @@
1
+ /**
2
+ * State Serializer for Five VM Account Data
3
+ *
4
+ * Serializes state account data based on Five account field definitions.
5
+ * Handles conversion of JavaScript types to Five VM bytecode format.
6
+ */
7
+ export interface StateFieldDefinition {
8
+ name: string;
9
+ type: string;
10
+ }
11
+ export interface StateDefinition {
12
+ name: string;
13
+ fields: StateFieldDefinition[];
14
+ }
15
+ /**
16
+ * Serializes state account data to Five VM bytecode format
17
+ */
18
+ export declare class StateSerializer {
19
+ /**
20
+ * Serialize complete state object based on definition
21
+ */
22
+ static serialize(stateDefinition: StateDefinition, data: Record<string, any>, options?: {
23
+ debug?: boolean;
24
+ }): Uint8Array;
25
+ /**
26
+ * Serialize a single field value based on its type
27
+ */
28
+ static serializeField(type: string, value: any, options?: {
29
+ debug?: boolean;
30
+ }): Uint8Array;
31
+ /**
32
+ * Serialize an integer value (u8, u16, u32, u64, i8, i16, i32, i64)
33
+ */
34
+ private static serializeInteger;
35
+ /**
36
+ * Serialize a public key (base58 to 32-byte array)
37
+ */
38
+ private static serializePubkey;
39
+ /**
40
+ * Serialize a UTF-8 string with length prefix
41
+ * Format: u32 length (little-endian) + UTF-8 bytes
42
+ */
43
+ private static serializeString;
44
+ /**
45
+ * Serialize an array of values
46
+ */
47
+ private static serializeArray;
48
+ /**
49
+ * Get default value for a type
50
+ */
51
+ private static getDefaultValue;
52
+ /**
53
+ * Convert byte array to hex string for debugging
54
+ */
55
+ private static toHexString;
56
+ /**
57
+ * Calculate total size of a state based on definition
58
+ */
59
+ static calculateSize(stateDefinition: StateDefinition): number;
60
+ /**
61
+ * Get size of a single field type in bytes
62
+ */
63
+ private static getFieldSize;
64
+ }
65
+ export default StateSerializer;
@@ -0,0 +1,330 @@
1
+ /**
2
+ * State Serializer for Five VM Account Data
3
+ *
4
+ * Serializes state account data based on Five account field definitions.
5
+ * Handles conversion of JavaScript types to Five VM bytecode format.
6
+ */
7
+ import { Base58Utils } from '../crypto/index.js';
8
+ /**
9
+ * Serializes state account data to Five VM bytecode format
10
+ */
11
+ export class StateSerializer {
12
+ /**
13
+ * Serialize complete state object based on definition
14
+ */
15
+ static serialize(stateDefinition, data, options = {}) {
16
+ if (options.debug) {
17
+ console.log(`[StateSerializer] Serializing ${stateDefinition.name} with ${stateDefinition.fields.length} fields`);
18
+ }
19
+ // Collect all field buffers
20
+ let totalSize = 0;
21
+ const fieldBuffers = [];
22
+ for (const field of stateDefinition.fields) {
23
+ const value = data[field.name];
24
+ if (value === undefined) {
25
+ if (options.debug) {
26
+ console.warn(`[StateSerializer] Field "${field.name}" not provided, using default value for type ${field.type}`);
27
+ }
28
+ // Use default value based on type
29
+ const defaultValue = this.getDefaultValue(field.type);
30
+ const buffer = this.serializeField(field.type, defaultValue, options);
31
+ fieldBuffers.push(buffer);
32
+ totalSize += buffer.length;
33
+ }
34
+ else {
35
+ const buffer = this.serializeField(field.type, value, options);
36
+ fieldBuffers.push(buffer);
37
+ totalSize += buffer.length;
38
+ }
39
+ }
40
+ // Concatenate all field buffers in order
41
+ const result = new Uint8Array(totalSize);
42
+ let offset = 0;
43
+ for (const buffer of fieldBuffers) {
44
+ result.set(buffer, offset);
45
+ offset += buffer.length;
46
+ }
47
+ if (options.debug) {
48
+ console.log(`[StateSerializer] Serialized to ${totalSize} bytes, hex: ${this.toHexString(result)}`);
49
+ }
50
+ return result;
51
+ }
52
+ /**
53
+ * Serialize a single field value based on its type
54
+ */
55
+ static serializeField(type, value, options = {}) {
56
+ // Normalize type name (remove whitespace, convert to lowercase)
57
+ const normalizedType = type.toLowerCase().trim();
58
+ if (options.debug) {
59
+ console.log(`[StateSerializer] Serializing field type="${normalizedType}" value="${value}"`);
60
+ }
61
+ // Handle integer types
62
+ if (normalizedType === 'u8' || normalizedType === 'u16' ||
63
+ normalizedType === 'u32' || normalizedType === 'u64' ||
64
+ normalizedType === 'i8' || normalizedType === 'i16' ||
65
+ normalizedType === 'i32' || normalizedType === 'i64') {
66
+ return this.serializeInteger(normalizedType, value);
67
+ }
68
+ // Handle boolean type
69
+ if (normalizedType === 'bool' || normalizedType === 'boolean') {
70
+ return new Uint8Array([value ? 1 : 0]);
71
+ }
72
+ // Handle public key type
73
+ if (normalizedType === 'pubkey' || normalizedType === 'publickey' ||
74
+ normalizedType === 'publickey' || normalizedType === 'account') {
75
+ return this.serializePubkey(value);
76
+ }
77
+ // Handle string type (UTF-8 encoded with length prefix)
78
+ if (normalizedType === 'string') {
79
+ return this.serializeString(value);
80
+ }
81
+ // Handle array types
82
+ if (normalizedType.endsWith('[]')) {
83
+ const elementType = normalizedType.slice(0, -2);
84
+ return this.serializeArray(elementType, value, options);
85
+ }
86
+ throw new Error(`Unsupported type: ${type}`);
87
+ }
88
+ /**
89
+ * Serialize an integer value (u8, u16, u32, u64, i8, i16, i32, i64)
90
+ */
91
+ static serializeInteger(type, value) {
92
+ let numValue;
93
+ if (typeof value === 'string') {
94
+ // Try parsing as BigInt first for 64-bit values
95
+ try {
96
+ numValue = BigInt(value);
97
+ }
98
+ catch {
99
+ numValue = parseInt(value, 10);
100
+ }
101
+ }
102
+ else {
103
+ numValue = value;
104
+ }
105
+ // Determine size based on type
106
+ let size;
107
+ let isSigned;
108
+ switch (type) {
109
+ case 'u8':
110
+ size = 1;
111
+ isSigned = false;
112
+ break;
113
+ case 'u16':
114
+ size = 2;
115
+ isSigned = false;
116
+ break;
117
+ case 'u32':
118
+ size = 4;
119
+ isSigned = false;
120
+ break;
121
+ case 'u64':
122
+ size = 8;
123
+ isSigned = false;
124
+ break;
125
+ case 'i8':
126
+ size = 1;
127
+ isSigned = true;
128
+ break;
129
+ case 'i16':
130
+ size = 2;
131
+ isSigned = true;
132
+ break;
133
+ case 'i32':
134
+ size = 4;
135
+ isSigned = true;
136
+ break;
137
+ case 'i64':
138
+ size = 8;
139
+ isSigned = true;
140
+ break;
141
+ default:
142
+ throw new Error(`Unsupported integer type: ${type}`);
143
+ }
144
+ const buffer = new Uint8Array(size);
145
+ const view = new DataView(buffer.buffer);
146
+ // Write value in little-endian format
147
+ if (size === 8 && typeof numValue === 'bigint') {
148
+ if (isSigned) {
149
+ view.setBigInt64(0, numValue, true);
150
+ }
151
+ else {
152
+ view.setBigUint64(0, numValue, true);
153
+ }
154
+ }
155
+ else {
156
+ const numericValue = typeof numValue === 'bigint' ? Number(numValue) : numValue;
157
+ switch (type) {
158
+ case 'u8':
159
+ view.setUint8(0, numericValue);
160
+ break;
161
+ case 'u16':
162
+ view.setUint16(0, numericValue, true);
163
+ break;
164
+ case 'u32':
165
+ view.setUint32(0, numericValue, true);
166
+ break;
167
+ case 'u64':
168
+ view.setBigUint64(0, BigInt(numericValue), true);
169
+ break;
170
+ case 'i8':
171
+ view.setInt8(0, numericValue);
172
+ break;
173
+ case 'i16':
174
+ view.setInt16(0, numericValue, true);
175
+ break;
176
+ case 'i32':
177
+ view.setInt32(0, numericValue, true);
178
+ break;
179
+ case 'i64':
180
+ view.setBigInt64(0, BigInt(numericValue), true);
181
+ break;
182
+ }
183
+ }
184
+ return buffer;
185
+ }
186
+ /**
187
+ * Serialize a public key (base58 to 32-byte array)
188
+ */
189
+ static serializePubkey(value) {
190
+ if (value instanceof Uint8Array) {
191
+ if (value.length !== 32) {
192
+ throw new Error(`Invalid pubkey: expected 32 bytes, got ${value.length}`);
193
+ }
194
+ return value;
195
+ }
196
+ try {
197
+ // Assume base58-encoded public key string
198
+ const decoded = Base58Utils.decode(value);
199
+ if (decoded.length !== 32) {
200
+ throw new Error(`Invalid pubkey: expected 32 bytes after decoding, got ${decoded.length}`);
201
+ }
202
+ return decoded;
203
+ }
204
+ catch (error) {
205
+ const errorMessage = error instanceof Error ? error.message : String(error);
206
+ throw new Error(`Failed to decode pubkey: ${errorMessage}`);
207
+ }
208
+ }
209
+ /**
210
+ * Serialize a UTF-8 string with length prefix
211
+ * Format: u32 length (little-endian) + UTF-8 bytes
212
+ */
213
+ static serializeString(value) {
214
+ const encoder = new TextEncoder();
215
+ const stringBytes = encoder.encode(value);
216
+ const length = stringBytes.length;
217
+ // Create buffer: 4 bytes for length + string bytes
218
+ const buffer = new Uint8Array(4 + length);
219
+ const view = new DataView(buffer.buffer);
220
+ // Write length as u32 in little-endian
221
+ view.setUint32(0, length, true);
222
+ // Write string bytes
223
+ buffer.set(stringBytes, 4);
224
+ return buffer;
225
+ }
226
+ /**
227
+ * Serialize an array of values
228
+ */
229
+ static serializeArray(elementType, values, options = {}) {
230
+ const elementBuffers = [];
231
+ let totalSize = 4; // 4 bytes for array length
232
+ // First, serialize all elements
233
+ for (const value of values) {
234
+ const buffer = this.serializeField(elementType, value, options);
235
+ elementBuffers.push(buffer);
236
+ totalSize += buffer.length;
237
+ }
238
+ // Create result buffer with length prefix
239
+ const result = new Uint8Array(totalSize);
240
+ const view = new DataView(result.buffer);
241
+ // Write array length as u32 in little-endian
242
+ view.setUint32(0, values.length, true);
243
+ // Write all elements
244
+ let offset = 4;
245
+ for (const buffer of elementBuffers) {
246
+ result.set(buffer, offset);
247
+ offset += buffer.length;
248
+ }
249
+ return result;
250
+ }
251
+ /**
252
+ * Get default value for a type
253
+ */
254
+ static getDefaultValue(type) {
255
+ const normalizedType = type.toLowerCase().trim();
256
+ if (normalizedType === 'bool' || normalizedType === 'boolean') {
257
+ return false;
258
+ }
259
+ if (normalizedType === 'u8' || normalizedType === 'u16' ||
260
+ normalizedType === 'u32' || normalizedType === 'u64' ||
261
+ normalizedType === 'i8' || normalizedType === 'i16' ||
262
+ normalizedType === 'i32' || normalizedType === 'i64') {
263
+ return 0;
264
+ }
265
+ if (normalizedType === 'pubkey' || normalizedType === 'publickey' ||
266
+ normalizedType === 'account') {
267
+ return '11111111111111111111111111111111'; // Default system program
268
+ }
269
+ if (normalizedType === 'string') {
270
+ return '';
271
+ }
272
+ if (normalizedType.endsWith('[]')) {
273
+ return [];
274
+ }
275
+ return null;
276
+ }
277
+ /**
278
+ * Convert byte array to hex string for debugging
279
+ */
280
+ static toHexString(bytes) {
281
+ return Array.from(bytes)
282
+ .map(byte => byte.toString(16).padStart(2, '0'))
283
+ .join('');
284
+ }
285
+ /**
286
+ * Calculate total size of a state based on definition
287
+ */
288
+ static calculateSize(stateDefinition) {
289
+ let totalSize = 0;
290
+ for (const field of stateDefinition.fields) {
291
+ totalSize += this.getFieldSize(field.type);
292
+ }
293
+ return totalSize;
294
+ }
295
+ /**
296
+ * Get size of a single field type in bytes
297
+ */
298
+ static getFieldSize(type) {
299
+ const normalizedType = type.toLowerCase().trim();
300
+ switch (normalizedType) {
301
+ case 'u8':
302
+ case 'i8':
303
+ case 'bool':
304
+ return 1;
305
+ case 'u16':
306
+ case 'i16':
307
+ return 2;
308
+ case 'u32':
309
+ case 'i32':
310
+ return 4;
311
+ case 'u64':
312
+ case 'i64':
313
+ return 8;
314
+ case 'pubkey':
315
+ case 'publickey':
316
+ case 'account':
317
+ return 32;
318
+ case 'string':
319
+ // Variable-length, return minimum (4 bytes for length)
320
+ return 4;
321
+ default:
322
+ if (normalizedType.endsWith('[]')) {
323
+ // Variable-length array
324
+ return 4; // Minimum for length prefix
325
+ }
326
+ throw new Error(`Unsupported type: ${type}`);
327
+ }
328
+ }
329
+ }
330
+ export default StateSerializer;