@5ive-tech/sdk 1.1.8 → 1.1.10
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/dist/FiveSDK.d.ts +17 -0
- package/dist/FiveSDK.js +11 -0
- package/dist/assets/vm/five_vm_wasm_bg.wasm +0 -0
- package/dist/assets/vm/five_vm_wasm_bg.wasm.d.ts +5 -5
- package/dist/crypto/index.js +2 -10
- package/dist/modules/admin.d.ts +121 -0
- package/dist/modules/admin.js +327 -0
- package/dist/modules/deploy.d.ts +17 -0
- package/dist/modules/deploy.js +294 -241
- package/dist/modules/execute.d.ts +4 -0
- package/dist/modules/execute.js +104 -94
- package/dist/modules/fees.d.ts +2 -0
- package/dist/modules/fees.js +21 -19
- package/dist/modules/vm-state.d.ts +4 -0
- package/dist/modules/vm-state.js +9 -2
- package/package.json +3 -2
- package/dist/assets/vm/dummy.file +0 -0
- package/dist/assets/vm/five_vm_wasm_bg.js +0 -3307
package/dist/modules/deploy.js
CHANGED
|
@@ -3,6 +3,75 @@ import { validator, Validators } from "../validation/index.js";
|
|
|
3
3
|
import { calculateDeployFee } from "./fees.js";
|
|
4
4
|
import { pollForConfirmation } from "../utils/transaction.js";
|
|
5
5
|
import { ProgramIdResolver } from "../config/ProgramIdResolver.js";
|
|
6
|
+
const DEFAULT_FEE_VAULT_SHARD_COUNT = 10;
|
|
7
|
+
const FEE_VAULT_NAMESPACE_SEED = Buffer.from([
|
|
8
|
+
0xff, 0x66, 0x69, 0x76, 0x65, 0x5f, 0x76, 0x6d, 0x5f, 0x66, 0x65, 0x65,
|
|
9
|
+
0x5f, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x76, 0x31,
|
|
10
|
+
]);
|
|
11
|
+
async function readVMStateFeeConfig(connection, vmStateAddress) {
|
|
12
|
+
if (!connection) {
|
|
13
|
+
return { shardCount: DEFAULT_FEE_VAULT_SHARD_COUNT };
|
|
14
|
+
}
|
|
15
|
+
try {
|
|
16
|
+
const { PublicKey } = await import("@solana/web3.js");
|
|
17
|
+
const info = await connection.getAccountInfo(new PublicKey(vmStateAddress), "confirmed");
|
|
18
|
+
if (!info) {
|
|
19
|
+
return { shardCount: DEFAULT_FEE_VAULT_SHARD_COUNT };
|
|
20
|
+
}
|
|
21
|
+
const data = new Uint8Array(info.data);
|
|
22
|
+
if (data.length < 56) {
|
|
23
|
+
return { shardCount: DEFAULT_FEE_VAULT_SHARD_COUNT };
|
|
24
|
+
}
|
|
25
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
26
|
+
const deployFeeLamports = view.getUint32(40, true);
|
|
27
|
+
const shardCountRaw = data.length > 50 ? data[50] : 0;
|
|
28
|
+
const shardCount = shardCountRaw > 0 ? shardCountRaw : DEFAULT_FEE_VAULT_SHARD_COUNT;
|
|
29
|
+
return { deployFeeLamports, shardCount };
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return { shardCount: DEFAULT_FEE_VAULT_SHARD_COUNT };
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
async function deriveProgramFeeVault(programId, shardIndex) {
|
|
36
|
+
const { PublicKey } = await import("@solana/web3.js");
|
|
37
|
+
const [pda, bump] = PublicKey.findProgramAddressSync([FEE_VAULT_NAMESPACE_SEED, Buffer.from([shardIndex])], new PublicKey(programId));
|
|
38
|
+
return { address: pda.toBase58(), bump };
|
|
39
|
+
}
|
|
40
|
+
function createInitFeeVaultInstructionData(shardIndex, bump) {
|
|
41
|
+
return Uint8Array.from([11, shardIndex & 0xff, bump & 0xff]);
|
|
42
|
+
}
|
|
43
|
+
async function initProgramFeeVaultShards(connection, programId, vmStateAccount, shardCount, payer, options = {}) {
|
|
44
|
+
const { PublicKey, Transaction, TransactionInstruction, SystemProgram } = await import("@solana/web3.js");
|
|
45
|
+
const signatures = [];
|
|
46
|
+
for (let shardIndex = 0; shardIndex < shardCount; shardIndex++) {
|
|
47
|
+
const vault = await deriveProgramFeeVault(programId, shardIndex);
|
|
48
|
+
const tx = new Transaction().add(new TransactionInstruction({
|
|
49
|
+
programId: new PublicKey(programId),
|
|
50
|
+
keys: [
|
|
51
|
+
{ pubkey: new PublicKey(vmStateAccount), isSigner: false, isWritable: false },
|
|
52
|
+
{ pubkey: payer.publicKey, isSigner: true, isWritable: true },
|
|
53
|
+
{ pubkey: new PublicKey(vault.address), isSigner: false, isWritable: true },
|
|
54
|
+
{ pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
|
|
55
|
+
],
|
|
56
|
+
data: Buffer.from(createInitFeeVaultInstructionData(shardIndex, vault.bump)),
|
|
57
|
+
}));
|
|
58
|
+
const { blockhash } = await connection.getLatestBlockhash("confirmed");
|
|
59
|
+
tx.recentBlockhash = blockhash;
|
|
60
|
+
tx.feePayer = payer.publicKey;
|
|
61
|
+
tx.partialSign(payer);
|
|
62
|
+
const sig = await connection.sendRawTransaction(tx.serialize(), {
|
|
63
|
+
skipPreflight: true,
|
|
64
|
+
preflightCommitment: "confirmed",
|
|
65
|
+
maxRetries: options.maxRetries || 3,
|
|
66
|
+
});
|
|
67
|
+
await connection.confirmTransaction(sig, "confirmed");
|
|
68
|
+
signatures.push(sig);
|
|
69
|
+
if (options.debug) {
|
|
70
|
+
console.log(`[FiveSDK] Initialized fee vault shard ${shardIndex}: ${vault.address}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return signatures;
|
|
74
|
+
}
|
|
6
75
|
export async function generateDeployInstruction(bytecode, deployer, options = {}, connection, fiveVMProgramId) {
|
|
7
76
|
Validators.bytecode(bytecode);
|
|
8
77
|
validator.validateBase58Address(deployer, "deployer");
|
|
@@ -29,24 +98,21 @@ export async function generateDeployInstruction(bytecode, deployer, options = {}
|
|
|
29
98
|
const SCRIPT_HEADER_SIZE = 64; // ScriptAccountHeader size from Rust program
|
|
30
99
|
const totalAccountSize = SCRIPT_HEADER_SIZE + exportMetadata.length + bytecode.length;
|
|
31
100
|
const rentLamports = await RentCalculator.calculateRentExemption(totalAccountSize);
|
|
101
|
+
const { deployFeeLamports } = await readVMStateFeeConfig(connection, vmStatePDA);
|
|
102
|
+
const deployShardIndex = 0;
|
|
103
|
+
const deployVault = await deriveProgramFeeVault(programId, deployShardIndex);
|
|
32
104
|
const deployAccounts = [
|
|
33
105
|
{ pubkey: scriptAccount, isSigner: false, isWritable: true },
|
|
34
106
|
{ pubkey: vmStatePDA, isSigner: false, isWritable: true },
|
|
35
107
|
{ pubkey: deployer, isSigner: true, isWritable: true },
|
|
36
|
-
{
|
|
37
|
-
pubkey: "11111111111111111111111111111112",
|
|
38
|
-
isSigner: false,
|
|
39
|
-
isWritable: false,
|
|
40
|
-
},
|
|
108
|
+
{ pubkey: deployVault.address, isSigner: false, isWritable: true },
|
|
41
109
|
];
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
const instructionData = encodeDeployInstruction(bytecode, options.permissions || 0, exportMetadata);
|
|
110
|
+
deployAccounts.push({
|
|
111
|
+
pubkey: "11111111111111111111111111111111",
|
|
112
|
+
isSigner: false,
|
|
113
|
+
isWritable: false,
|
|
114
|
+
});
|
|
115
|
+
const instructionData = encodeDeployInstruction(bytecode, options.permissions || 0, exportMetadata, deployShardIndex, deployVault.bump);
|
|
50
116
|
const result = {
|
|
51
117
|
programId: programId,
|
|
52
118
|
instruction: {
|
|
@@ -110,14 +176,12 @@ options = {}) {
|
|
|
110
176
|
const exportMetadata = encodeExportMetadata(options.exportMetadata);
|
|
111
177
|
const totalAccountSize = SCRIPT_HEADER_SIZE + exportMetadata.length + bytecode.length;
|
|
112
178
|
const rentLamports = await connection.getMinimumBalanceForRentExemption(totalAccountSize);
|
|
113
|
-
|
|
114
|
-
const
|
|
115
|
-
const VM_STATE_SIZE = 56; // FIVEVMState::LEN
|
|
116
|
-
const vmStateRent = await connection.getMinimumBalanceForRentExemption(VM_STATE_SIZE);
|
|
179
|
+
const vmStatePDA = await PDAUtils.deriveVMStatePDA(programIdStr);
|
|
180
|
+
const vmStatePubkey = new PublicKey(vmStatePDA.address);
|
|
117
181
|
if (options.debug) {
|
|
118
182
|
console.log(`[FiveSDK] Preparing deployment transaction:`);
|
|
119
183
|
console.log(` - Script Account: ${scriptAccount}`);
|
|
120
|
-
console.log(` - VM State Account: ${
|
|
184
|
+
console.log(` - VM State Account: ${vmStatePubkey.toString()}`);
|
|
121
185
|
console.log(` - Deployer: ${deployerPublicKey.toString()}`);
|
|
122
186
|
}
|
|
123
187
|
const tx = new Transaction();
|
|
@@ -127,24 +191,21 @@ options = {}) {
|
|
|
127
191
|
units: options.computeBudget,
|
|
128
192
|
}));
|
|
129
193
|
}
|
|
130
|
-
// 1.
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
data: Buffer.from([0]), // Initialize discriminator
|
|
146
|
-
}));
|
|
147
|
-
// 3. Create Script Account
|
|
194
|
+
// 1. Initialize canonical VM State if missing
|
|
195
|
+
const vmStateInfo = await connection.getAccountInfo(vmStatePubkey);
|
|
196
|
+
if (!vmStateInfo) {
|
|
197
|
+
tx.add(new TransactionInstruction({
|
|
198
|
+
keys: [
|
|
199
|
+
{ pubkey: vmStatePubkey, isSigner: false, isWritable: true },
|
|
200
|
+
{ pubkey: deployerPublicKey, isSigner: true, isWritable: false },
|
|
201
|
+
{ pubkey: deployerPublicKey, isSigner: true, isWritable: true },
|
|
202
|
+
{ pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
|
|
203
|
+
],
|
|
204
|
+
programId: programId,
|
|
205
|
+
data: buildInitializeVmStateInstructionData(vmStatePDA.bump),
|
|
206
|
+
}));
|
|
207
|
+
}
|
|
208
|
+
// 2. Create Script Account
|
|
148
209
|
tx.add(SystemProgram.createAccount({
|
|
149
210
|
fromPubkey: deployerPublicKey,
|
|
150
211
|
newAccountPubkey: scriptKeypair.publicKey,
|
|
@@ -152,12 +213,12 @@ options = {}) {
|
|
|
152
213
|
space: totalAccountSize,
|
|
153
214
|
programId: programId,
|
|
154
215
|
}));
|
|
155
|
-
//
|
|
216
|
+
// 3. Deploy Instruction
|
|
156
217
|
const deployData = encodeDeployInstruction(bytecode, 0, exportMetadata);
|
|
157
218
|
tx.add(new TransactionInstruction({
|
|
158
219
|
keys: [
|
|
159
220
|
{ pubkey: scriptKeypair.publicKey, isSigner: false, isWritable: true },
|
|
160
|
-
{ pubkey:
|
|
221
|
+
{ pubkey: vmStatePubkey, isSigner: false, isWritable: true },
|
|
161
222
|
{ pubkey: deployerPublicKey, isSigner: true, isWritable: true },
|
|
162
223
|
],
|
|
163
224
|
programId: programId,
|
|
@@ -168,11 +229,10 @@ options = {}) {
|
|
|
168
229
|
tx.feePayer = deployerPublicKey;
|
|
169
230
|
// Partial sign with generated keys
|
|
170
231
|
tx.partialSign(scriptKeypair);
|
|
171
|
-
tx.partialSign(vmStateKeypair);
|
|
172
232
|
return {
|
|
173
233
|
transaction: tx,
|
|
174
234
|
scriptKeypair,
|
|
175
|
-
vmStateKeypair,
|
|
235
|
+
vmStateKeypair: null,
|
|
176
236
|
programId: scriptAccount,
|
|
177
237
|
rentLamports,
|
|
178
238
|
};
|
|
@@ -200,22 +260,28 @@ options = {}) {
|
|
|
200
260
|
const exportMetadata = encodeExportMetadata(options.exportMetadata);
|
|
201
261
|
const totalAccountSize = SCRIPT_HEADER_SIZE + exportMetadata.length + bytecode.length;
|
|
202
262
|
const rentLamports = await connection.getMinimumBalanceForRentExemption(totalAccountSize);
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
263
|
+
const vmStateResolution = await ensureCanonicalVmStateAccount(connection, deployerKeypair, new PublicKey(programId), {
|
|
264
|
+
vmStateAccount: options.vmStateAccount,
|
|
265
|
+
maxRetries: options.maxRetries,
|
|
266
|
+
debug: options.debug,
|
|
267
|
+
});
|
|
268
|
+
const vmStatePubkey = vmStateResolution.vmStatePubkey;
|
|
269
|
+
const vmStateRent = vmStateResolution.vmStateRent;
|
|
270
|
+
const vmStateFeeConfig = await readVMStateFeeConfig(connection, vmStatePubkey.toString());
|
|
271
|
+
const deployShardIndex = 0;
|
|
272
|
+
const deployVault = await deriveProgramFeeVault(programId, deployShardIndex);
|
|
273
|
+
const feeVaultKeys = [
|
|
274
|
+
{
|
|
275
|
+
pubkey: new PublicKey(deployVault.address),
|
|
276
|
+
isSigner: false,
|
|
277
|
+
isWritable: true,
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
pubkey: SystemProgram.programId,
|
|
281
|
+
isSigner: false,
|
|
282
|
+
isWritable: false,
|
|
283
|
+
},
|
|
284
|
+
];
|
|
219
285
|
if (options.debug) {
|
|
220
286
|
console.log(`[FiveSDK] Script Account: ${scriptAccount}`);
|
|
221
287
|
console.log(`[FiveSDK] VM State Account: ${vmStatePubkey.toString()}`);
|
|
@@ -223,7 +289,8 @@ options = {}) {
|
|
|
223
289
|
console.log(`[FiveSDK] Export metadata size: ${exportMetadata.length} bytes`);
|
|
224
290
|
console.log(`[FiveSDK] Rent cost: ${((rentLamports + vmStateRent) / 1e9)} SOL`);
|
|
225
291
|
}
|
|
226
|
-
|
|
292
|
+
const feeVaultInitSigs = await initProgramFeeVaultShards(connection, programId, vmStatePubkey.toString(), vmStateFeeConfig.shardCount, deployerKeypair, { debug: options.debug, maxRetries: options.maxRetries });
|
|
293
|
+
// SINGLE TRANSACTION: create script account + deploy bytecode
|
|
227
294
|
const tx = new Transaction();
|
|
228
295
|
// Optional compute budget
|
|
229
296
|
if (options.computeBudget && options.computeBudget > 0) {
|
|
@@ -235,36 +302,7 @@ options = {}) {
|
|
|
235
302
|
}
|
|
236
303
|
catch { }
|
|
237
304
|
}
|
|
238
|
-
|
|
239
|
-
// 1) Create VM state account owned by the program
|
|
240
|
-
const createVmStateIx = SystemProgram.createAccount({
|
|
241
|
-
fromPubkey: deployerKeypair.publicKey,
|
|
242
|
-
newAccountPubkey: vmStatePubkey,
|
|
243
|
-
lamports: vmStateRent,
|
|
244
|
-
space: VM_STATE_SIZE,
|
|
245
|
-
programId: new PublicKey(programId),
|
|
246
|
-
});
|
|
247
|
-
tx.add(createVmStateIx);
|
|
248
|
-
// 2) Initialize VM state: [discriminator(0)] with accounts [vm_state, authority]
|
|
249
|
-
const initVmStateIx = new TransactionInstruction({
|
|
250
|
-
keys: [
|
|
251
|
-
{
|
|
252
|
-
pubkey: vmStatePubkey,
|
|
253
|
-
isSigner: false,
|
|
254
|
-
isWritable: true,
|
|
255
|
-
},
|
|
256
|
-
{
|
|
257
|
-
pubkey: deployerKeypair.publicKey,
|
|
258
|
-
isSigner: true,
|
|
259
|
-
isWritable: false,
|
|
260
|
-
},
|
|
261
|
-
],
|
|
262
|
-
programId: new PublicKey(programId),
|
|
263
|
-
data: Buffer.from([0]), // Initialize discriminator
|
|
264
|
-
});
|
|
265
|
-
tx.add(initVmStateIx);
|
|
266
|
-
}
|
|
267
|
-
// 3) Create script account
|
|
305
|
+
// 1) Create script account
|
|
268
306
|
const createAccountIx = SystemProgram.createAccount({
|
|
269
307
|
fromPubkey: deployerKeypair.publicKey,
|
|
270
308
|
newAccountPubkey: scriptKeypair.publicKey,
|
|
@@ -273,7 +311,7 @@ options = {}) {
|
|
|
273
311
|
programId: new PublicKey(programId),
|
|
274
312
|
});
|
|
275
313
|
tx.add(createAccountIx);
|
|
276
|
-
const deployData = encodeDeployInstruction(bytecode, 0, exportMetadata);
|
|
314
|
+
const deployData = encodeDeployInstruction(bytecode, 0, exportMetadata, deployShardIndex, deployVault.bump);
|
|
277
315
|
const instructionDataBuffer = Buffer.from(deployData);
|
|
278
316
|
const deployIx = new TransactionInstruction({
|
|
279
317
|
keys: [
|
|
@@ -292,6 +330,16 @@ options = {}) {
|
|
|
292
330
|
isSigner: true,
|
|
293
331
|
isWritable: true,
|
|
294
332
|
},
|
|
333
|
+
{
|
|
334
|
+
pubkey: new PublicKey(deployVault.address),
|
|
335
|
+
isSigner: false,
|
|
336
|
+
isWritable: true,
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
pubkey: SystemProgram.programId,
|
|
340
|
+
isSigner: false,
|
|
341
|
+
isWritable: false,
|
|
342
|
+
},
|
|
295
343
|
],
|
|
296
344
|
programId: new PublicKey(programId),
|
|
297
345
|
data: instructionDataBuffer,
|
|
@@ -301,9 +349,6 @@ options = {}) {
|
|
|
301
349
|
tx.recentBlockhash = blockhash;
|
|
302
350
|
tx.feePayer = deployerKeypair.publicKey;
|
|
303
351
|
tx.partialSign(deployerKeypair);
|
|
304
|
-
if (!options.vmStateAccount) {
|
|
305
|
-
tx.partialSign(vmStateKeypair);
|
|
306
|
-
}
|
|
307
352
|
tx.partialSign(scriptKeypair);
|
|
308
353
|
const txSerialized = tx.serialize();
|
|
309
354
|
if (options.debug) {
|
|
@@ -347,13 +392,14 @@ options = {}) {
|
|
|
347
392
|
success: true,
|
|
348
393
|
programId: scriptAccount,
|
|
349
394
|
transactionId: signature,
|
|
350
|
-
deploymentCost: rentLamports,
|
|
395
|
+
deploymentCost: rentLamports + vmStateRent,
|
|
351
396
|
logs: [
|
|
352
397
|
`Script Account: ${scriptAccount}`,
|
|
353
398
|
`Deployment TX: ${signature}`,
|
|
354
399
|
`Deployment cost (rent): ${rentLamports / 1e9} SOL`,
|
|
355
400
|
`Bytecode size: ${bytecode.length} bytes`,
|
|
356
401
|
`VM State Account: ${vmStatePubkey.toString()}`,
|
|
402
|
+
`Fee vault shards initialized: ${feeVaultInitSigs.length}`,
|
|
357
403
|
],
|
|
358
404
|
vmStateAccount: vmStatePubkey.toString(),
|
|
359
405
|
};
|
|
@@ -380,7 +426,7 @@ options = {}) {
|
|
|
380
426
|
console.log(`[FiveSDK] options:`, options);
|
|
381
427
|
try {
|
|
382
428
|
// If bytecode is small enough, use regular deployment
|
|
383
|
-
if (bytecode.length <= 800) {
|
|
429
|
+
if (bytecode.length <= 800 && !options.forceChunkedSmallProgram) {
|
|
384
430
|
if (options.debug) {
|
|
385
431
|
console.log(`[FiveSDK] Bytecode is small (${bytecode.length} bytes), using regular deployment`);
|
|
386
432
|
}
|
|
@@ -390,6 +436,7 @@ options = {}) {
|
|
|
390
436
|
maxRetries: options.maxRetries,
|
|
391
437
|
fiveVMProgramId: options.fiveVMProgramId,
|
|
392
438
|
vmStateAccount: options.vmStateAccount,
|
|
439
|
+
adminAccount: options.adminAccount,
|
|
393
440
|
});
|
|
394
441
|
}
|
|
395
442
|
const { Keypair, PublicKey, Transaction, TransactionInstruction, SystemProgram, } = await import("@solana/web3.js");
|
|
@@ -402,76 +449,37 @@ options = {}) {
|
|
|
402
449
|
const rentLamports = await connection.getMinimumBalanceForRentExemption(totalAccountSize);
|
|
403
450
|
const programIdStr = ProgramIdResolver.resolve(options.fiveVMProgramId);
|
|
404
451
|
const programId = new PublicKey(programIdStr);
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
452
|
+
const vmStateResolution = await ensureCanonicalVmStateAccount(connection, deployerKeypair, programId, {
|
|
453
|
+
vmStateAccount: options.vmStateAccount,
|
|
454
|
+
maxRetries: options.maxRetries,
|
|
455
|
+
debug: options.debug,
|
|
456
|
+
});
|
|
457
|
+
const vmStatePubkey = vmStateResolution.vmStatePubkey;
|
|
458
|
+
const vmStateRent = vmStateResolution.vmStateRent;
|
|
459
|
+
const vmStateFeeConfig = await readVMStateFeeConfig(connection, vmStatePubkey.toString());
|
|
460
|
+
const deployShardIndex = 0;
|
|
461
|
+
const deployVault = await deriveProgramFeeVault(programIdStr, deployShardIndex);
|
|
462
|
+
const feeVaultKeys = [
|
|
463
|
+
{
|
|
464
|
+
pubkey: new PublicKey(deployVault.address),
|
|
465
|
+
isSigner: false,
|
|
466
|
+
isWritable: true,
|
|
467
|
+
},
|
|
468
|
+
{
|
|
469
|
+
pubkey: SystemProgram.programId,
|
|
470
|
+
isSigner: false,
|
|
471
|
+
isWritable: false,
|
|
472
|
+
},
|
|
473
|
+
];
|
|
422
474
|
if (options.debug) {
|
|
423
475
|
console.log(`[FiveSDK] Script Account: ${scriptAccount}`);
|
|
424
476
|
console.log(`[FiveSDK] VM State Account: ${vmStatePubkey.toString()}`);
|
|
425
477
|
console.log(`[FiveSDK] Total account size: ${totalAccountSize} bytes`);
|
|
426
478
|
console.log(`[FiveSDK] Initial rent cost: ${(rentLamports + vmStateRent) / 1e9} SOL`);
|
|
427
479
|
}
|
|
480
|
+
const feeVaultInitSigs = await initProgramFeeVaultShards(connection, programIdStr, vmStatePubkey.toString(), vmStateFeeConfig.shardCount, deployerKeypair, { debug: options.debug, maxRetries: options.maxRetries });
|
|
428
481
|
const transactionIds = [];
|
|
429
482
|
let totalCost = rentLamports + vmStateRent;
|
|
430
|
-
// TRANSACTION 0: Create VM State Account + Initialize (ONLY IF CREATING NEW)
|
|
431
|
-
if (!options.vmStateAccount) {
|
|
432
|
-
if (options.debug) {
|
|
433
|
-
console.log(`[FiveSDK] Step 0: Create VM state account and initialize`);
|
|
434
|
-
}
|
|
435
|
-
const vmStateTransaction = new Transaction();
|
|
436
|
-
vmStateTransaction.add(SystemProgram.createAccount({
|
|
437
|
-
fromPubkey: deployerKeypair.publicKey,
|
|
438
|
-
newAccountPubkey: vmStateKeypair.publicKey,
|
|
439
|
-
lamports: vmStateRent,
|
|
440
|
-
space: VM_STATE_SIZE,
|
|
441
|
-
programId: programId,
|
|
442
|
-
}));
|
|
443
|
-
vmStateTransaction.add(new TransactionInstruction({
|
|
444
|
-
keys: [
|
|
445
|
-
{
|
|
446
|
-
pubkey: vmStateKeypair.publicKey,
|
|
447
|
-
isSigner: false,
|
|
448
|
-
isWritable: true,
|
|
449
|
-
},
|
|
450
|
-
{
|
|
451
|
-
pubkey: deployerKeypair.publicKey,
|
|
452
|
-
isSigner: true,
|
|
453
|
-
isWritable: false,
|
|
454
|
-
},
|
|
455
|
-
],
|
|
456
|
-
programId: programId,
|
|
457
|
-
data: Buffer.from([0]), // Initialize discriminator
|
|
458
|
-
}));
|
|
459
|
-
vmStateTransaction.feePayer = deployerKeypair.publicKey;
|
|
460
|
-
const vmStateBlockhash = await connection.getLatestBlockhash("confirmed");
|
|
461
|
-
vmStateTransaction.recentBlockhash = vmStateBlockhash.blockhash;
|
|
462
|
-
vmStateTransaction.partialSign(deployerKeypair);
|
|
463
|
-
vmStateTransaction.partialSign(vmStateKeypair);
|
|
464
|
-
const vmStateSignature = await connection.sendRawTransaction(vmStateTransaction.serialize(), {
|
|
465
|
-
skipPreflight: true,
|
|
466
|
-
preflightCommitment: "confirmed",
|
|
467
|
-
maxRetries: options.maxRetries || 3,
|
|
468
|
-
});
|
|
469
|
-
await connection.confirmTransaction(vmStateSignature, "confirmed");
|
|
470
|
-
transactionIds.push(vmStateSignature);
|
|
471
|
-
if (options.debug) {
|
|
472
|
-
console.log(`[FiveSDK] ✅ VM state initialized: ${vmStateSignature}`);
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
483
|
// TRANSACTION 1: Create Account + InitLargeProgram
|
|
476
484
|
if (options.debug) {
|
|
477
485
|
console.log(`[FiveSDK] Step 1: Create account and initialize large program`);
|
|
@@ -487,10 +495,7 @@ options = {}) {
|
|
|
487
495
|
});
|
|
488
496
|
initTransaction.add(createAccountInstruction);
|
|
489
497
|
// Add InitLargeProgram instruction (discriminator 4 + expected_size as u32)
|
|
490
|
-
const initInstructionData =
|
|
491
|
-
Buffer.from([4]), // InitLargeProgram discriminator
|
|
492
|
-
Buffer.from(new Uint32Array([bytecode.length]).buffer), // expected_size as little-endian u32
|
|
493
|
-
]);
|
|
498
|
+
const initInstructionData = createInitLargeProgramInstructionData(bytecode.length);
|
|
494
499
|
const initLargeProgramInstruction = new TransactionInstruction({
|
|
495
500
|
keys: [
|
|
496
501
|
{
|
|
@@ -506,8 +511,9 @@ options = {}) {
|
|
|
506
511
|
{
|
|
507
512
|
pubkey: vmStatePubkey,
|
|
508
513
|
isSigner: false,
|
|
509
|
-
isWritable:
|
|
514
|
+
isWritable: false,
|
|
510
515
|
},
|
|
516
|
+
...feeVaultKeys,
|
|
511
517
|
],
|
|
512
518
|
programId: programId,
|
|
513
519
|
data: initInstructionData,
|
|
@@ -587,10 +593,7 @@ options = {}) {
|
|
|
587
593
|
totalCost += additionalRent;
|
|
588
594
|
}
|
|
589
595
|
// Add AppendBytecode instruction (discriminator 5 + chunk data)
|
|
590
|
-
const appendInstructionData =
|
|
591
|
-
Buffer.from([5]), // AppendBytecode discriminator
|
|
592
|
-
chunk,
|
|
593
|
-
]);
|
|
596
|
+
const appendInstructionData = createAppendBytecodeInstructionData(chunk);
|
|
594
597
|
const appendBytecodeInstruction = new TransactionInstruction({
|
|
595
598
|
keys: [
|
|
596
599
|
{
|
|
@@ -606,8 +609,9 @@ options = {}) {
|
|
|
606
609
|
{
|
|
607
610
|
pubkey: vmStatePubkey,
|
|
608
611
|
isSigner: false,
|
|
609
|
-
isWritable:
|
|
612
|
+
isWritable: false,
|
|
610
613
|
},
|
|
614
|
+
...feeVaultKeys,
|
|
611
615
|
],
|
|
612
616
|
programId: programId,
|
|
613
617
|
data: appendInstructionData,
|
|
@@ -648,6 +652,7 @@ options = {}) {
|
|
|
648
652
|
vmStateAccount: vmStatePubkey.toString(),
|
|
649
653
|
logs: [
|
|
650
654
|
`Deployed ${bytecode.length} bytes in ${chunks.length} chunks using ${transactionIds.length} transactions`,
|
|
655
|
+
`Fee vault shards initialized: ${feeVaultInitSigs.length}`,
|
|
651
656
|
],
|
|
652
657
|
};
|
|
653
658
|
}
|
|
@@ -675,7 +680,7 @@ options = {}) {
|
|
|
675
680
|
console.log(`[FiveSDK] Expected optimization: 50-70% fewer transactions`);
|
|
676
681
|
try {
|
|
677
682
|
// If bytecode is small enough, use regular deployment
|
|
678
|
-
if (bytecode.length <= 800) {
|
|
683
|
+
if (bytecode.length <= 800 && !options.forceChunkedSmallProgram) {
|
|
679
684
|
if (options.debug) {
|
|
680
685
|
console.log(`[FiveSDK] Bytecode is small (${bytecode.length} bytes), using regular deployment`);
|
|
681
686
|
}
|
|
@@ -683,6 +688,10 @@ options = {}) {
|
|
|
683
688
|
debug: options.debug,
|
|
684
689
|
network: options.network,
|
|
685
690
|
maxRetries: options.maxRetries,
|
|
691
|
+
fiveVMProgramId: options.fiveVMProgramId,
|
|
692
|
+
vmStateAccount: options.vmStateAccount,
|
|
693
|
+
adminAccount: options.adminAccount,
|
|
694
|
+
exportMetadata: options.exportMetadata,
|
|
686
695
|
});
|
|
687
696
|
}
|
|
688
697
|
const { Keypair, PublicKey, Transaction, TransactionInstruction, SystemProgram, } = await import("@solana/web3.js");
|
|
@@ -690,72 +699,42 @@ options = {}) {
|
|
|
690
699
|
const scriptKeypair = Keypair.generate();
|
|
691
700
|
const scriptAccount = scriptKeypair.publicKey.toString();
|
|
692
701
|
// Calculate full account size upfront
|
|
693
|
-
const SCRIPT_HEADER_SIZE =
|
|
702
|
+
const SCRIPT_HEADER_SIZE = 64; // ScriptAccountHeader::LEN
|
|
694
703
|
const totalAccountSize = SCRIPT_HEADER_SIZE + bytecode.length;
|
|
695
704
|
const rentLamports = await connection.getMinimumBalanceForRentExemption(totalAccountSize);
|
|
696
705
|
const programIdStr = ProgramIdResolver.resolve(options.fiveVMProgramId);
|
|
697
706
|
const programId = new PublicKey(programIdStr);
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
707
|
+
const vmStateResolution = await ensureCanonicalVmStateAccount(connection, deployerKeypair, programId, {
|
|
708
|
+
vmStateAccount: options.vmStateAccount,
|
|
709
|
+
maxRetries: options.maxRetries,
|
|
710
|
+
debug: options.debug,
|
|
711
|
+
});
|
|
712
|
+
const vmStatePubkey = vmStateResolution.vmStatePubkey;
|
|
713
|
+
const vmStateRent = vmStateResolution.vmStateRent;
|
|
714
|
+
const vmStateFeeConfig = await readVMStateFeeConfig(connection, vmStatePubkey.toString());
|
|
715
|
+
const deployShardIndex = 0;
|
|
716
|
+
const deployVault = await deriveProgramFeeVault(programIdStr, deployShardIndex);
|
|
717
|
+
const feeVaultKeys = [
|
|
718
|
+
{
|
|
719
|
+
pubkey: new PublicKey(deployVault.address),
|
|
720
|
+
isSigner: false,
|
|
721
|
+
isWritable: true,
|
|
722
|
+
},
|
|
723
|
+
{
|
|
724
|
+
pubkey: SystemProgram.programId,
|
|
725
|
+
isSigner: false,
|
|
726
|
+
isWritable: false,
|
|
727
|
+
},
|
|
728
|
+
];
|
|
702
729
|
if (options.debug) {
|
|
703
730
|
console.log(`[FiveSDK] Script Account: ${scriptAccount}`);
|
|
704
|
-
console.log(`[FiveSDK] VM State Account: ${
|
|
731
|
+
console.log(`[FiveSDK] VM State Account: ${vmStatePubkey.toString()}`);
|
|
705
732
|
console.log(`[FiveSDK] PRE-ALLOCATED full account size: ${totalAccountSize} bytes`);
|
|
706
733
|
console.log(`[FiveSDK] Full rent cost paid upfront: ${(rentLamports + vmStateRent) / 1e9} SOL`);
|
|
707
734
|
}
|
|
735
|
+
const feeVaultInitSigs = await initProgramFeeVaultShards(connection, programIdStr, vmStatePubkey.toString(), vmStateFeeConfig.shardCount, deployerKeypair, { debug: options.debug, maxRetries: options.maxRetries });
|
|
708
736
|
const transactionIds = [];
|
|
709
737
|
let totalCost = rentLamports + vmStateRent;
|
|
710
|
-
if (options.debug) {
|
|
711
|
-
console.log(`[FiveSDK] Create VM state account and initialize`);
|
|
712
|
-
}
|
|
713
|
-
const vmStateTransaction = new Transaction();
|
|
714
|
-
vmStateTransaction.add(SystemProgram.createAccount({
|
|
715
|
-
fromPubkey: deployerKeypair.publicKey,
|
|
716
|
-
newAccountPubkey: vmStateKeypair.publicKey,
|
|
717
|
-
lamports: vmStateRent,
|
|
718
|
-
space: VM_STATE_SIZE,
|
|
719
|
-
programId: programId,
|
|
720
|
-
}));
|
|
721
|
-
vmStateTransaction.add(new TransactionInstruction({
|
|
722
|
-
keys: [
|
|
723
|
-
{
|
|
724
|
-
pubkey: vmStateKeypair.publicKey,
|
|
725
|
-
isSigner: false,
|
|
726
|
-
isWritable: true,
|
|
727
|
-
},
|
|
728
|
-
{
|
|
729
|
-
pubkey: deployerKeypair.publicKey,
|
|
730
|
-
isSigner: true,
|
|
731
|
-
isWritable: false,
|
|
732
|
-
},
|
|
733
|
-
],
|
|
734
|
-
programId: programId,
|
|
735
|
-
data: Buffer.from([0]), // Initialize discriminator
|
|
736
|
-
}));
|
|
737
|
-
vmStateTransaction.feePayer = deployerKeypair.publicKey;
|
|
738
|
-
const vmStateBlockhash = await connection.getLatestBlockhash("confirmed");
|
|
739
|
-
vmStateTransaction.recentBlockhash = vmStateBlockhash.blockhash;
|
|
740
|
-
vmStateTransaction.partialSign(deployerKeypair);
|
|
741
|
-
vmStateTransaction.partialSign(vmStateKeypair);
|
|
742
|
-
const vmStateSignature = await connection.sendRawTransaction(vmStateTransaction.serialize(), {
|
|
743
|
-
skipPreflight: true,
|
|
744
|
-
preflightCommitment: "confirmed",
|
|
745
|
-
maxRetries: options.maxRetries || 3,
|
|
746
|
-
});
|
|
747
|
-
const vmStateConfirmation = await pollForConfirmation(connection, vmStateSignature, "confirmed", 120000, options.debug);
|
|
748
|
-
if (!vmStateConfirmation.success) {
|
|
749
|
-
return {
|
|
750
|
-
success: false,
|
|
751
|
-
error: `VM state initialization confirmation failed: ${vmStateConfirmation.error}`,
|
|
752
|
-
transactionIds: [vmStateSignature]
|
|
753
|
-
};
|
|
754
|
-
}
|
|
755
|
-
transactionIds.push(vmStateSignature);
|
|
756
|
-
if (options.debug) {
|
|
757
|
-
console.log(`[FiveSDK] ✅ VM state initialized: ${vmStateSignature}`);
|
|
758
|
-
}
|
|
759
738
|
const chunks = chunkBytecode(bytecode, chunkSize);
|
|
760
739
|
const firstChunk = chunks[0];
|
|
761
740
|
const remainingChunks = chunks.slice(1);
|
|
@@ -774,13 +753,7 @@ options = {}) {
|
|
|
774
753
|
programId: programId,
|
|
775
754
|
});
|
|
776
755
|
initTransaction.add(createAccountInstruction);
|
|
777
|
-
const
|
|
778
|
-
sizeBuffer.writeUInt32LE(bytecode.length, 0);
|
|
779
|
-
const initInstructionData = Buffer.concat([
|
|
780
|
-
Buffer.from([4]), // InitLargeProgramWithChunk discriminator (same as InitLargeProgram)
|
|
781
|
-
sizeBuffer,
|
|
782
|
-
firstChunk,
|
|
783
|
-
]);
|
|
756
|
+
const initInstructionData = createInitLargeProgramInstructionData(bytecode.length, firstChunk);
|
|
784
757
|
const initLargeProgramWithChunkInstruction = new TransactionInstruction({
|
|
785
758
|
keys: [
|
|
786
759
|
{
|
|
@@ -794,10 +767,11 @@ options = {}) {
|
|
|
794
767
|
isWritable: true,
|
|
795
768
|
},
|
|
796
769
|
{
|
|
797
|
-
pubkey:
|
|
770
|
+
pubkey: vmStatePubkey,
|
|
798
771
|
isSigner: false,
|
|
799
|
-
isWritable:
|
|
772
|
+
isWritable: false,
|
|
800
773
|
},
|
|
774
|
+
...feeVaultKeys,
|
|
801
775
|
],
|
|
802
776
|
programId: programId,
|
|
803
777
|
data: initInstructionData,
|
|
@@ -847,10 +821,7 @@ options = {}) {
|
|
|
847
821
|
if (options.debug) {
|
|
848
822
|
console.log(`[FiveSDK] Using single-chunk AppendBytecode for remaining chunk (${chunkGroup[0].length} bytes)`);
|
|
849
823
|
}
|
|
850
|
-
const singleChunkData =
|
|
851
|
-
Buffer.from([5]), // AppendBytecode discriminator
|
|
852
|
-
Buffer.from(chunkGroup[0]),
|
|
853
|
-
]);
|
|
824
|
+
const singleChunkData = createAppendBytecodeInstructionData(chunkGroup[0]);
|
|
854
825
|
appendInstruction = new TransactionInstruction({
|
|
855
826
|
keys: [
|
|
856
827
|
{
|
|
@@ -864,10 +835,11 @@ options = {}) {
|
|
|
864
835
|
isWritable: true,
|
|
865
836
|
},
|
|
866
837
|
{
|
|
867
|
-
pubkey:
|
|
838
|
+
pubkey: vmStatePubkey,
|
|
868
839
|
isSigner: false,
|
|
869
840
|
isWritable: true,
|
|
870
841
|
},
|
|
842
|
+
...feeVaultKeys,
|
|
871
843
|
],
|
|
872
844
|
programId: programId,
|
|
873
845
|
data: singleChunkData,
|
|
@@ -889,10 +861,11 @@ options = {}) {
|
|
|
889
861
|
isWritable: true,
|
|
890
862
|
},
|
|
891
863
|
{
|
|
892
|
-
pubkey:
|
|
864
|
+
pubkey: vmStatePubkey,
|
|
893
865
|
isSigner: false,
|
|
894
866
|
isWritable: true,
|
|
895
867
|
},
|
|
868
|
+
...feeVaultKeys,
|
|
896
869
|
],
|
|
897
870
|
programId: programId,
|
|
898
871
|
data: multiChunkData,
|
|
@@ -941,9 +914,10 @@ options = {}) {
|
|
|
941
914
|
isSigner: true,
|
|
942
915
|
isWritable: true,
|
|
943
916
|
},
|
|
917
|
+
...feeVaultKeys,
|
|
944
918
|
],
|
|
945
919
|
programId: programId,
|
|
946
|
-
data:
|
|
920
|
+
data: createFinalizeScriptInstructionData(),
|
|
947
921
|
}));
|
|
948
922
|
finalizeTransaction.feePayer = deployerKeypair.publicKey;
|
|
949
923
|
const finalizeBlockhash = await connection.getLatestBlockhash("confirmed");
|
|
@@ -983,7 +957,7 @@ options = {}) {
|
|
|
983
957
|
totalTransactions: optimizedTransactionCount,
|
|
984
958
|
deploymentCost: totalCost,
|
|
985
959
|
chunksUsed: chunks.length,
|
|
986
|
-
vmStateAccount:
|
|
960
|
+
vmStateAccount: vmStatePubkey.toString(),
|
|
987
961
|
optimizationSavings: {
|
|
988
962
|
transactionsSaved,
|
|
989
963
|
estimatedCostSaved,
|
|
@@ -994,6 +968,7 @@ options = {}) {
|
|
|
994
968
|
`💰 Cost: ${totalCost / 1e9} SOL`,
|
|
995
969
|
`🧩 Chunks: ${chunks.length}`,
|
|
996
970
|
`⚡ Optimization: ${Math.round((transactionsSaved / traditionalTransactionCount) * 100)}% fewer transactions`,
|
|
971
|
+
`🏦 Fee vault shards initialized: ${feeVaultInitSigs.length}`,
|
|
997
972
|
],
|
|
998
973
|
};
|
|
999
974
|
}
|
|
@@ -1007,18 +982,24 @@ options = {}) {
|
|
|
1007
982
|
};
|
|
1008
983
|
}
|
|
1009
984
|
}
|
|
1010
|
-
function encodeDeployInstruction(bytecode, permissions = 0, metadata = new Uint8Array()) {
|
|
985
|
+
function encodeDeployInstruction(bytecode, permissions = 0, metadata = new Uint8Array(), feeShardIndex = 0, feeVaultBump) {
|
|
1011
986
|
const lengthBuffer = Buffer.allocUnsafe(4);
|
|
1012
987
|
lengthBuffer.writeUInt32LE(bytecode.length, 0);
|
|
1013
988
|
const metadataLenBuffer = Buffer.allocUnsafe(4);
|
|
1014
989
|
metadataLenBuffer.writeUInt32LE(metadata.length, 0);
|
|
1015
|
-
const
|
|
990
|
+
const hasFeeTrailer = typeof feeVaultBump === "number";
|
|
991
|
+
const result = new Uint8Array(1 + 4 + 1 + 4 + metadata.length + bytecode.length + (hasFeeTrailer ? 2 : 0));
|
|
1016
992
|
result[0] = 8; // Deploy discriminator (matches on-chain FIVE program)
|
|
1017
993
|
result.set(new Uint8Array(lengthBuffer), 1); // u32 LE length at bytes 1-4
|
|
1018
994
|
result[5] = permissions; // permissions byte at byte 5
|
|
1019
995
|
result.set(new Uint8Array(metadataLenBuffer), 6); // metadata length at bytes 6-9
|
|
1020
996
|
result.set(metadata, 10);
|
|
1021
997
|
result.set(bytecode, 10 + metadata.length);
|
|
998
|
+
if (hasFeeTrailer) {
|
|
999
|
+
const trailerOffset = 10 + metadata.length + bytecode.length;
|
|
1000
|
+
result[trailerOffset] = feeShardIndex & 0xff;
|
|
1001
|
+
result[trailerOffset + 1] = feeVaultBump & 0xff;
|
|
1002
|
+
}
|
|
1022
1003
|
console.log(`[FiveSDK] Deploy instruction encoded:`, {
|
|
1023
1004
|
discriminator: result[0],
|
|
1024
1005
|
lengthBytes: Array.from(new Uint8Array(lengthBuffer)),
|
|
@@ -1026,7 +1007,7 @@ function encodeDeployInstruction(bytecode, permissions = 0, metadata = new Uint8
|
|
|
1026
1007
|
metadataLength: metadata.length,
|
|
1027
1008
|
bytecodeLength: bytecode.length,
|
|
1028
1009
|
totalInstructionLength: result.length,
|
|
1029
|
-
expectedFormat: `[8, ${bytecode.length}_as_u32le, 0x${permissions.toString(16).padStart(2, '0')}, ${metadata.length}_as_u32le, metadata_bytes, bytecode_bytes]`,
|
|
1010
|
+
expectedFormat: `[8, ${bytecode.length}_as_u32le, 0x${permissions.toString(16).padStart(2, '0')}, ${metadata.length}_as_u32le, metadata_bytes, bytecode_bytes, optional(shard,bump)]`,
|
|
1030
1011
|
instructionHex: Buffer.from(result).toString("hex").substring(0, 20) + "...",
|
|
1031
1012
|
});
|
|
1032
1013
|
return result;
|
|
@@ -1068,6 +1049,54 @@ function encodeExportMetadata(input) {
|
|
|
1068
1049
|
}
|
|
1069
1050
|
return Uint8Array.from(out);
|
|
1070
1051
|
}
|
|
1052
|
+
async function ensureCanonicalVmStateAccount(connection, deployerKeypair, programId, options = {}) {
|
|
1053
|
+
const { PublicKey, Transaction, TransactionInstruction, SystemProgram } = await import("@solana/web3.js");
|
|
1054
|
+
const canonical = await PDAUtils.deriveVMStatePDA(programId.toString());
|
|
1055
|
+
if (options.vmStateAccount && options.vmStateAccount !== canonical.address) {
|
|
1056
|
+
throw new Error(`vmStateAccount must be canonical PDA ${canonical.address}; got ${options.vmStateAccount}`);
|
|
1057
|
+
}
|
|
1058
|
+
const vmStatePubkey = new PublicKey(canonical.address);
|
|
1059
|
+
const existing = await connection.getAccountInfo(vmStatePubkey);
|
|
1060
|
+
if (existing) {
|
|
1061
|
+
if (existing.owner.toBase58() !== programId.toBase58()) {
|
|
1062
|
+
throw new Error(`canonical VM state ${canonical.address} exists but is owned by ${existing.owner.toBase58()}, expected ${programId.toBase58()}`);
|
|
1063
|
+
}
|
|
1064
|
+
if (options.debug) {
|
|
1065
|
+
console.log(`[FiveSDK] Reusing canonical VM State PDA: ${canonical.address}`);
|
|
1066
|
+
}
|
|
1067
|
+
return { vmStatePubkey, vmStateRent: 0, created: false, bump: canonical.bump };
|
|
1068
|
+
}
|
|
1069
|
+
const VM_STATE_SIZE = 56;
|
|
1070
|
+
const vmStateRent = await connection.getMinimumBalanceForRentExemption(VM_STATE_SIZE);
|
|
1071
|
+
if (options.debug) {
|
|
1072
|
+
console.log(`[FiveSDK] Initializing canonical VM State PDA: ${canonical.address}`);
|
|
1073
|
+
}
|
|
1074
|
+
const initTransaction = new Transaction();
|
|
1075
|
+
initTransaction.add(new TransactionInstruction({
|
|
1076
|
+
keys: [
|
|
1077
|
+
{ pubkey: vmStatePubkey, isSigner: false, isWritable: true },
|
|
1078
|
+
{ pubkey: deployerKeypair.publicKey, isSigner: true, isWritable: false },
|
|
1079
|
+
{ pubkey: deployerKeypair.publicKey, isSigner: true, isWritable: true },
|
|
1080
|
+
{ pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
|
|
1081
|
+
],
|
|
1082
|
+
programId,
|
|
1083
|
+
data: buildInitializeVmStateInstructionData(canonical.bump),
|
|
1084
|
+
}));
|
|
1085
|
+
initTransaction.feePayer = deployerKeypair.publicKey;
|
|
1086
|
+
const initBlockhash = await connection.getLatestBlockhash("confirmed");
|
|
1087
|
+
initTransaction.recentBlockhash = initBlockhash.blockhash;
|
|
1088
|
+
initTransaction.partialSign(deployerKeypair);
|
|
1089
|
+
const initSignature = await connection.sendRawTransaction(initTransaction.serialize(), {
|
|
1090
|
+
skipPreflight: true,
|
|
1091
|
+
preflightCommitment: "confirmed",
|
|
1092
|
+
maxRetries: options.maxRetries || 3,
|
|
1093
|
+
});
|
|
1094
|
+
const initConfirmation = await pollForConfirmation(connection, initSignature, "confirmed", 120000, options.debug);
|
|
1095
|
+
if (!initConfirmation.success || initConfirmation.err) {
|
|
1096
|
+
throw new Error(`canonical VM state initialization failed: ${initConfirmation.error || JSON.stringify(initConfirmation.err)}`);
|
|
1097
|
+
}
|
|
1098
|
+
return { vmStatePubkey, vmStateRent, created: true, bump: canonical.bump };
|
|
1099
|
+
}
|
|
1071
1100
|
function chunkBytecode(bytecode, chunkSize) {
|
|
1072
1101
|
const chunks = [];
|
|
1073
1102
|
for (let i = 0; i < bytecode.length; i += chunkSize) {
|
|
@@ -1116,3 +1145,27 @@ function createMultiChunkInstructionData(chunks) {
|
|
|
1116
1145
|
}
|
|
1117
1146
|
return Buffer.concat(buffers);
|
|
1118
1147
|
}
|
|
1148
|
+
function buildInitializeVmStateInstructionData(bump = 0) {
|
|
1149
|
+
return Buffer.from([0, bump & 0xff]);
|
|
1150
|
+
}
|
|
1151
|
+
function createInitLargeProgramInstructionData(expectedSize, firstChunk) {
|
|
1152
|
+
const sizeBuffer = Buffer.allocUnsafe(4);
|
|
1153
|
+
sizeBuffer.writeUInt32LE(expectedSize, 0);
|
|
1154
|
+
const parts = [Buffer.from([4]), sizeBuffer];
|
|
1155
|
+
if (firstChunk && firstChunk.length > 0) {
|
|
1156
|
+
parts.push(Buffer.from(firstChunk));
|
|
1157
|
+
}
|
|
1158
|
+
return Buffer.concat(parts);
|
|
1159
|
+
}
|
|
1160
|
+
function createAppendBytecodeInstructionData(chunk) {
|
|
1161
|
+
return Buffer.concat([Buffer.from([5]), Buffer.from(chunk)]);
|
|
1162
|
+
}
|
|
1163
|
+
function createFinalizeScriptInstructionData() {
|
|
1164
|
+
return Buffer.from([7]);
|
|
1165
|
+
}
|
|
1166
|
+
export const __deployTestUtils = {
|
|
1167
|
+
buildInitializeVmStateInstructionData,
|
|
1168
|
+
createInitLargeProgramInstructionData,
|
|
1169
|
+
createAppendBytecodeInstructionData,
|
|
1170
|
+
createFinalizeScriptInstructionData,
|
|
1171
|
+
};
|