@usearete/adapter-kit 0.16.0 → 0.17.0
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 +38 -2
- package/dist/index.cjs +557 -80
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +132 -9
- package/dist/index.js +545 -83
- package/dist/index.js.map +1 -1
- package/package.json +7 -6
package/dist/index.cjs
CHANGED
|
@@ -3,6 +3,111 @@
|
|
|
3
3
|
var kit = require('@solana/kit');
|
|
4
4
|
var sdk = require('@usearete/sdk');
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Wallet Standard → kit signer bridge.
|
|
8
|
+
*
|
|
9
|
+
* The handoff is byte-oriented on purpose: the app picks the transaction
|
|
10
|
+
* format, the wallet decodes the version out of the bytes it is given, and
|
|
11
|
+
* Arete forwards whatever came back without converting versions. Nothing
|
|
12
|
+
* here routes a transaction through a web3.js 1.x wrapper, which cannot
|
|
13
|
+
* represent V1 at all.
|
|
14
|
+
*
|
|
15
|
+
* The capability check is a local fact about the wallet, not proof the
|
|
16
|
+
* cluster has activated a version: the account must advertise
|
|
17
|
+
* `solana:signTransaction`, and *that* feature must advertise the version
|
|
18
|
+
* being signed. Sign-and-send support is never read as sign-only support —
|
|
19
|
+
* a wallet that can only sign-and-send cannot hand bytes back for Arete to
|
|
20
|
+
* relay.
|
|
21
|
+
*
|
|
22
|
+
* As of Kit 8, the upstream Wallet Standard `signTransaction` feature still
|
|
23
|
+
* types `supportedTransactionVersions` as `legacy | 0`. The interfaces below
|
|
24
|
+
* are therefore declared structurally rather than imported, so a wallet that
|
|
25
|
+
* does advertise `1` is usable without a cast and one that does not is
|
|
26
|
+
* refused before it is ever prompted.
|
|
27
|
+
*/
|
|
28
|
+
/** The feature name a sign-only handoff requires. */
|
|
29
|
+
const SOLANA_SIGN_TRANSACTION = 'solana:signTransaction';
|
|
30
|
+
/** The feature name that is explicitly *not* evidence of sign-only support. */
|
|
31
|
+
const SOLANA_SIGN_AND_SEND_TRANSACTION = 'solana:signAndSendTransaction';
|
|
32
|
+
/** Typed refusal from the Wallet Standard bridge. */
|
|
33
|
+
class WalletStandardSignerError extends Error {
|
|
34
|
+
constructor(code, message) {
|
|
35
|
+
super(message);
|
|
36
|
+
this.name = 'WalletStandardSignerError';
|
|
37
|
+
this.code = code;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function readSignTransactionFeature(config) {
|
|
41
|
+
if (!config.account.features.includes(SOLANA_SIGN_TRANSACTION)) {
|
|
42
|
+
const signAndSendOnly = config.account.features.includes(SOLANA_SIGN_AND_SEND_TRANSACTION);
|
|
43
|
+
throw new WalletStandardSignerError('sign_transaction_unsupported', `Account ${config.account.address} does not support '${SOLANA_SIGN_TRANSACTION}'`
|
|
44
|
+
+ (signAndSendOnly
|
|
45
|
+
? `; it advertises only '${SOLANA_SIGN_AND_SEND_TRANSACTION}', which cannot return `
|
|
46
|
+
+ 'signed bytes for Arete to relay'
|
|
47
|
+
: ''));
|
|
48
|
+
}
|
|
49
|
+
const feature = config.wallet.features[SOLANA_SIGN_TRANSACTION];
|
|
50
|
+
if (!feature || typeof feature.signTransaction !== 'function') {
|
|
51
|
+
throw new WalletStandardSignerError('sign_transaction_unsupported', `Wallet does not implement the '${SOLANA_SIGN_TRANSACTION}' feature`);
|
|
52
|
+
}
|
|
53
|
+
return feature;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* A kit {@link TransactionSigner} backed by a Wallet Standard account.
|
|
57
|
+
*
|
|
58
|
+
* The feature is resolved once, at creation, so a wallet that cannot sign at
|
|
59
|
+
* all fails before any transaction is built. The per-version check happens
|
|
60
|
+
* per transaction, against the version decoded from the bytes about to be
|
|
61
|
+
* handed over — so a v0-only wallet refuses a V1 transaction without ever
|
|
62
|
+
* showing the user a prompt.
|
|
63
|
+
*/
|
|
64
|
+
function createWalletStandardSigner(config) {
|
|
65
|
+
const feature = readSignTransactionFeature(config);
|
|
66
|
+
const address = config.account.address;
|
|
67
|
+
return {
|
|
68
|
+
address,
|
|
69
|
+
async signTransactions(transactions) {
|
|
70
|
+
if (transactions.length === 0)
|
|
71
|
+
return [];
|
|
72
|
+
const inputs = transactions.map((transaction) => {
|
|
73
|
+
const version = kit.getTransactionVersionDecoder().decode(transaction.messageBytes);
|
|
74
|
+
if (!feature.supportedTransactionVersions.includes(version)) {
|
|
75
|
+
throw new WalletStandardSignerError('transaction_version_unsupported', `Wallet does not support signing transaction version ${JSON.stringify(version)} `
|
|
76
|
+
+ `(supported: ${feature.supportedTransactionVersions
|
|
77
|
+
.map((supported) => JSON.stringify(supported))
|
|
78
|
+
.join(', ')})`);
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
account: config.account,
|
|
82
|
+
chain: config.chain,
|
|
83
|
+
transaction: kit.getTransactionEncoder().encode(transaction),
|
|
84
|
+
};
|
|
85
|
+
});
|
|
86
|
+
const outputs = await feature.signTransaction(...inputs);
|
|
87
|
+
if (outputs.length !== transactions.length) {
|
|
88
|
+
throw new WalletStandardSignerError('wallet_returned_invalid_transaction', `Wallet returned ${outputs.length} signed transactions for ${transactions.length} `
|
|
89
|
+
+ 'inputs');
|
|
90
|
+
}
|
|
91
|
+
return outputs.map((output, index) => {
|
|
92
|
+
const returned = kit.getTransactionDecoder().decode(output.signedTransaction);
|
|
93
|
+
// A wallet may add signatures; it may not rewrite the message the
|
|
94
|
+
// app compiled. Anything else and the bytes Arete would relay are
|
|
95
|
+
// not the bytes the caller approved.
|
|
96
|
+
const original = transactions[index].messageBytes;
|
|
97
|
+
if (returned.messageBytes.length !== original.length
|
|
98
|
+
|| returned.messageBytes.some((byte, offset) => byte !== original[offset])) {
|
|
99
|
+
throw new WalletStandardSignerError('wallet_returned_invalid_transaction', 'Wallet returned a transaction whose message differs from the one it was given');
|
|
100
|
+
}
|
|
101
|
+
const signature = returned.signatures[address];
|
|
102
|
+
if (!signature) {
|
|
103
|
+
throw new WalletStandardSignerError('wallet_returned_invalid_transaction', `Wallet returned no signature for ${address}`);
|
|
104
|
+
}
|
|
105
|
+
return { [address]: signature };
|
|
106
|
+
});
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
6
111
|
/**
|
|
7
112
|
* @usearete/adapter-kit
|
|
8
113
|
*
|
|
@@ -14,13 +119,58 @@ var sdk = require('@usearete/sdk');
|
|
|
14
119
|
* sending, and confirmation.
|
|
15
120
|
*/
|
|
16
121
|
/**
|
|
17
|
-
* Kit
|
|
18
|
-
*
|
|
122
|
+
* Kit 8 is the first release that constructs transaction V1 messages and
|
|
123
|
+
* carries the resource budget as a typed message config, so this adapter
|
|
124
|
+
* builds every version the contract defines and honours every typed
|
|
125
|
+
* resource option.
|
|
19
126
|
*/
|
|
20
127
|
const CAPABILITY = {
|
|
21
|
-
supportedTransactionVersions: [0],
|
|
22
|
-
supportedResourceOptions: [
|
|
128
|
+
supportedTransactionVersions: ['legacy', 0, 1],
|
|
129
|
+
supportedResourceOptions: [
|
|
130
|
+
'computeUnitLimit',
|
|
131
|
+
'loadedAccountsDataSizeLimit',
|
|
132
|
+
'heapSize',
|
|
133
|
+
'priorityFeeLamports',
|
|
134
|
+
'computeUnitPriceMicroLamports',
|
|
135
|
+
],
|
|
23
136
|
};
|
|
137
|
+
/** Wire ceiling for legacy and v0 transactions, in bytes (one UDP packet). */
|
|
138
|
+
const LEGACY_TRANSACTION_SIZE_LIMIT = 1232;
|
|
139
|
+
/** Wire ceiling for V1 transactions, in bytes (SIMD-0385). */
|
|
140
|
+
const V1_TRANSACTION_SIZE_LIMIT = 4096;
|
|
141
|
+
/** Structural V1 caps enforced before a signer is reached (SIMD-0385). */
|
|
142
|
+
const V1_MAX_SIGNATURES = 12;
|
|
143
|
+
const V1_MAX_ACCOUNTS = 64;
|
|
144
|
+
const V1_MAX_INSTRUCTIONS = 64;
|
|
145
|
+
/**
|
|
146
|
+
* Per-transaction compute-unit maximum. Also the limit a *provisional* V1
|
|
147
|
+
* message declares for a budget the caller omitted: SIMD-0385 makes an unset
|
|
148
|
+
* V1 config field request the **minimum**, not a default, so a provisional
|
|
149
|
+
* message carrying nothing could never produce an ordinary successful
|
|
150
|
+
* execution estimate.
|
|
151
|
+
*/
|
|
152
|
+
const MAX_COMPUTE_UNIT_LIMIT = 1400000;
|
|
153
|
+
/** Loaded-account-data maximum (64 MiB), used the same way. */
|
|
154
|
+
const MAX_LOADED_ACCOUNTS_DATA_SIZE = 64 * 1024 * 1024;
|
|
155
|
+
/**
|
|
156
|
+
* Headroom added to measured compute consumption, in percent: a simulation
|
|
157
|
+
* is one slot's view of the chain and the transaction that lands may take a
|
|
158
|
+
* slightly different branch.
|
|
159
|
+
*/
|
|
160
|
+
const ESTIMATED_COMPUTE_UNIT_HEADROOM_PERCENT = 20n;
|
|
161
|
+
/**
|
|
162
|
+
* The runtime accounts for loaded data in pages of this size, so an
|
|
163
|
+
* estimated data budget is rounded up to a whole page plus one page of
|
|
164
|
+
* headroom for account growth between simulation and execution.
|
|
165
|
+
*/
|
|
166
|
+
const LOADED_ACCOUNTS_DATA_PAGE_BYTES = 32 * 1024;
|
|
167
|
+
const COMPUTE_BUDGET_PROGRAM_ADDRESS = 'ComputeBudget111111111111111111111111111111';
|
|
168
|
+
/** Option keys that would carry address lookup tables. */
|
|
169
|
+
const LOOKUP_TABLE_OPTION_KEYS = [
|
|
170
|
+
'addressLookupTables',
|
|
171
|
+
'addressLookupTableAccounts',
|
|
172
|
+
'lookupTables',
|
|
173
|
+
];
|
|
24
174
|
/** Structured adapter error consumed by the Arete transaction outcome APIs. */
|
|
25
175
|
class KitTransactionExecutionError extends Error {
|
|
26
176
|
constructor(outcome) {
|
|
@@ -93,14 +243,72 @@ function resolveTransport(selection, rpc, rpcSubscriptions, context) {
|
|
|
93
243
|
return { kind: 'direct', rpc, rpcSubscriptions };
|
|
94
244
|
throw new Error('No transaction transport is available; connect through Arete or configure direct RPC');
|
|
95
245
|
}
|
|
96
|
-
|
|
97
|
-
|
|
246
|
+
/**
|
|
247
|
+
* Report, never adopt, a relay signature that is not the one signed here.
|
|
248
|
+
*
|
|
249
|
+
* The adapter signs the final bytes and derives the signature from them, so
|
|
250
|
+
* the local one is authoritative. Reconciling an echoed signature would
|
|
251
|
+
* poll a transaction this adapter never submitted: it can report another
|
|
252
|
+
* transaction's status as this one's, or never confirm the one that went
|
|
253
|
+
* out.
|
|
254
|
+
*/
|
|
255
|
+
function reportSignatureMismatch(local, echoed) {
|
|
256
|
+
if (echoed && echoed !== local) {
|
|
257
|
+
// eslint-disable-next-line no-console -- the adapter has no logger, and
|
|
258
|
+
// this runs after the transaction may already be on the wire, so it
|
|
259
|
+
// must not interrupt the signature-bearing outcome.
|
|
260
|
+
console.warn(`Arete relay reported signature ${echoed} for a transaction signed as ${local}; `
|
|
261
|
+
+ 'the locally derived signature is authoritative and is the one being reconciled');
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
/** Thrown by {@link withDeadline} when the shared deadline passes first. */
|
|
265
|
+
class DeadlineExpiredError extends Error {
|
|
266
|
+
constructor() {
|
|
267
|
+
super('The configured confirmation deadline expired');
|
|
268
|
+
this.name = 'DeadlineExpiredError';
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
const DEADLINE_EXPIRED = Symbol('deadline-expired');
|
|
272
|
+
/**
|
|
273
|
+
* Await `work`, or give up at `deadline`.
|
|
274
|
+
*
|
|
275
|
+
* A racing timer rather than an abort signal: `TransactionTransport` takes
|
|
276
|
+
* none, and no HTTP client under it imposes a request timeout, so a backend
|
|
277
|
+
* that stops answering would otherwise hold the caller forever. The
|
|
278
|
+
* abandoned request is left with a no-op rejection handler — it may still be
|
|
279
|
+
* in flight, which is exactly why the outcome is *unknown* rather than
|
|
280
|
+
* failed.
|
|
281
|
+
*/
|
|
282
|
+
async function withDeadline(deadline, work) {
|
|
283
|
+
work.catch(() => { });
|
|
284
|
+
let timer;
|
|
285
|
+
// Executor form, not `Promise.withResolvers`: that landed in Node 22 and
|
|
286
|
+
// this package's floor is the Node 20.18 that Kit 8 requires.
|
|
287
|
+
const expiry = new Promise((resolve) => {
|
|
288
|
+
timer = setTimeout(() => resolve(DEADLINE_EXPIRED), Math.max(deadline - Date.now(), 0));
|
|
289
|
+
});
|
|
290
|
+
try {
|
|
291
|
+
const result = await Promise.race([work, expiry]);
|
|
292
|
+
if (result === DEADLINE_EXPIRED)
|
|
293
|
+
throw new DeadlineExpiredError();
|
|
294
|
+
return result;
|
|
295
|
+
}
|
|
296
|
+
finally {
|
|
297
|
+
clearTimeout(timer);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Poll until the signature reaches `commitment`, its lifetime expires, or
|
|
302
|
+
* `deadline` passes — including while a request is in flight. Never
|
|
303
|
+
* resubmits, and only ever polls the signature the caller signed.
|
|
304
|
+
*/
|
|
305
|
+
async function pollAreteStatus(transport, signature, commitment, lastValidBlockHeight, deadline, options) {
|
|
98
306
|
const interval = options?.statusPollIntervalMs ?? 500;
|
|
99
307
|
let emptyStatusPolls = 0;
|
|
100
308
|
while (Date.now() <= deadline) {
|
|
101
|
-
const status = await transport.getSignatureStatus(signature, {
|
|
309
|
+
const status = await withDeadline(deadline, transport.getSignatureStatus(signature, {
|
|
102
310
|
commitment, searchTransactionHistory: true,
|
|
103
|
-
});
|
|
311
|
+
}));
|
|
104
312
|
if (status?.err) {
|
|
105
313
|
throw new KitTransactionExecutionError({
|
|
106
314
|
status: 'chain-failed', phase: 'confirmation', signature,
|
|
@@ -110,7 +318,8 @@ async function pollAreteStatus(transport, signature, commitment, lastValidBlockH
|
|
|
110
318
|
if (status && hasReachedCommitment(status.confirmationStatus, commitment)) {
|
|
111
319
|
return { signature, slot: status.slot === null ? undefined : Number(status.slot) };
|
|
112
320
|
}
|
|
113
|
-
if (await transport.getBlockHeight({ commitment })
|
|
321
|
+
if (await withDeadline(deadline, transport.getBlockHeight({ commitment }))
|
|
322
|
+
> lastValidBlockHeight) {
|
|
114
323
|
throw new KitTransactionExecutionError({
|
|
115
324
|
status: 'submitted-unknown', phase: 'confirmation', signature,
|
|
116
325
|
slot: status?.slot === null ? undefined : Number(status?.slot),
|
|
@@ -118,7 +327,8 @@ async function pollAreteStatus(transport, signature, commitment, lastValidBlockH
|
|
|
118
327
|
});
|
|
119
328
|
}
|
|
120
329
|
emptyStatusPolls = status ? 0 : emptyStatusPolls + 1;
|
|
121
|
-
const
|
|
330
|
+
const backoffMs = Math.min(interval * (2 ** Math.min(emptyStatusPolls, 3)), 4000);
|
|
331
|
+
const delayMs = Math.min(backoffMs, Math.max(deadline - Date.now(), 0));
|
|
122
332
|
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
123
333
|
}
|
|
124
334
|
throw new KitTransactionExecutionError({
|
|
@@ -176,7 +386,7 @@ function fromAccountRole(role) {
|
|
|
176
386
|
return { isSigner: false, isWritable: false };
|
|
177
387
|
}
|
|
178
388
|
}
|
|
179
|
-
/** Convert an Arete BuiltInstruction to a kit
|
|
389
|
+
/** Convert an Arete BuiltInstruction to a kit Instruction. */
|
|
180
390
|
function toKitInstruction(ix) {
|
|
181
391
|
const accounts = ix.keys.map((k) => ({
|
|
182
392
|
address: kit.address(k.pubkey),
|
|
@@ -188,7 +398,7 @@ function toKitInstruction(ix) {
|
|
|
188
398
|
data: ix.data,
|
|
189
399
|
};
|
|
190
400
|
}
|
|
191
|
-
/** Convert a kit
|
|
401
|
+
/** Convert a kit Instruction to an Arete BuiltInstruction. */
|
|
192
402
|
function fromKitInstruction(ix) {
|
|
193
403
|
return {
|
|
194
404
|
programId: ix.programAddress,
|
|
@@ -199,6 +409,232 @@ function fromKitInstruction(ix) {
|
|
|
199
409
|
data: ix.data ? new Uint8Array(ix.data) : new Uint8Array(0),
|
|
200
410
|
};
|
|
201
411
|
}
|
|
412
|
+
// ---------------------------------------------------------------------------
|
|
413
|
+
// One version/configuration planner, shared by send and unsigned inspection
|
|
414
|
+
// ---------------------------------------------------------------------------
|
|
415
|
+
/**
|
|
416
|
+
* Refuse the inputs the typed configuration owns.
|
|
417
|
+
*
|
|
418
|
+
* A hand-built `ComputeBudget` instruction is not an effective V1
|
|
419
|
+
* configuration — the runtime reads V1 budgets from the message config — and
|
|
420
|
+
* silently accepting one would apply a budget on legacy/v0 and none on V1
|
|
421
|
+
* from the same caller code. Address lookup tables have no V1 encoding at
|
|
422
|
+
* all, and this adapter compiles none for any version.
|
|
423
|
+
*/
|
|
424
|
+
function assertBuildableInputs(instructions, options, version) {
|
|
425
|
+
if (instructions.length === 0) {
|
|
426
|
+
throw new Error('A transaction requires at least one instruction');
|
|
427
|
+
}
|
|
428
|
+
if (instructions.some((ix) => ix.programId === COMPUTE_BUDGET_PROGRAM_ADDRESS)) {
|
|
429
|
+
throw new Error('Caller-supplied ComputeBudget instructions are rejected: request compute units, heap '
|
|
430
|
+
+ 'size, loaded-accounts size and fees through the typed `resources` options so one '
|
|
431
|
+
+ 'contract covers every transaction version');
|
|
432
|
+
}
|
|
433
|
+
const lookupTableKey = LOOKUP_TABLE_OPTION_KEYS.find((key) => options?.[key] !== undefined);
|
|
434
|
+
if (lookupTableKey) {
|
|
435
|
+
throw new Error(`Address lookup tables are not supported by this adapter (rejected option `
|
|
436
|
+
+ `'${lookupTableKey}')`
|
|
437
|
+
+ (version === 1 ? '; transaction version 1 has no lookup tables at all (SIMD-0385)' : ''));
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
function toUnits(value) {
|
|
441
|
+
return value === undefined ? undefined : Number(value);
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* A V1 message: the resource budget is the message's typed config, and the
|
|
445
|
+
* runtime reads it from there — which is why a caller-supplied
|
|
446
|
+
* `ComputeBudget` instruction is rejected rather than merged.
|
|
447
|
+
*/
|
|
448
|
+
function planV1Message(input) {
|
|
449
|
+
const { resources } = input;
|
|
450
|
+
const configured = kit.setTransactionMessageConfig({
|
|
451
|
+
computeUnitLimit: toUnits(resources.computeUnitLimit),
|
|
452
|
+
heapSize: toUnits(resources.heapSize),
|
|
453
|
+
loadedAccountsDataSizeLimit: toUnits(resources.loadedAccountsDataSizeLimit),
|
|
454
|
+
priorityFeeLamports: resources.priorityFeeLamports,
|
|
455
|
+
}, kit.createTransactionMessage({ version: 1 }));
|
|
456
|
+
const withFeePayer = kit.setTransactionMessageFeePayerSigner(input.feePayer, configured);
|
|
457
|
+
const withLifetime = kit.setTransactionMessageLifetimeUsingBlockhash(input.latestBlockhash, withFeePayer);
|
|
458
|
+
return kit.appendTransactionMessageInstructions(input.instructions.map(toKitInstruction), withLifetime);
|
|
459
|
+
}
|
|
460
|
+
/**
|
|
461
|
+
* A legacy or v0 message: the same budget, rendered as the canonical
|
|
462
|
+
* `ComputeBudget` instructions kit prepends.
|
|
463
|
+
*/
|
|
464
|
+
function planLegacyMessage(input) {
|
|
465
|
+
const { resources } = input;
|
|
466
|
+
const created = input.version === 0
|
|
467
|
+
? kit.createTransactionMessage({ version: 0 })
|
|
468
|
+
: kit.createTransactionMessage({ version: 'legacy' });
|
|
469
|
+
const withFeePayer = kit.setTransactionMessageFeePayerSigner(input.feePayer, created);
|
|
470
|
+
const withLifetime = kit.setTransactionMessageLifetimeUsingBlockhash(input.latestBlockhash, withFeePayer);
|
|
471
|
+
let message = kit.appendTransactionMessageInstructions(input.instructions.map(toKitInstruction), withLifetime);
|
|
472
|
+
if (resources.computeUnitLimit !== undefined) {
|
|
473
|
+
message = kit.setTransactionMessageComputeUnitLimit(Number(resources.computeUnitLimit), message);
|
|
474
|
+
}
|
|
475
|
+
if (resources.computeUnitPriceMicroLamports !== undefined) {
|
|
476
|
+
message = kit.setTransactionMessageComputeUnitPrice(resources.computeUnitPriceMicroLamports, message);
|
|
477
|
+
}
|
|
478
|
+
if (resources.heapSize !== undefined) {
|
|
479
|
+
message = kit.setTransactionMessageHeapSize(Number(resources.heapSize), message);
|
|
480
|
+
}
|
|
481
|
+
if (resources.loadedAccountsDataSizeLimit !== undefined) {
|
|
482
|
+
message = kit.setTransactionMessageLoadedAccountsDataSizeLimit(Number(resources.loadedAccountsDataSizeLimit), message);
|
|
483
|
+
}
|
|
484
|
+
return message;
|
|
485
|
+
}
|
|
486
|
+
/**
|
|
487
|
+
* One version/configuration planner for send and unsigned inspection: the
|
|
488
|
+
* only difference between the two is whether the fee payer can sign.
|
|
489
|
+
*/
|
|
490
|
+
function planMessage(input) {
|
|
491
|
+
const message = input.version === 1 ? planV1Message(input) : planLegacyMessage(input);
|
|
492
|
+
return input.attachedSigners?.length
|
|
493
|
+
? kit.addSignersToTransactionMessage([...input.attachedSigners], message)
|
|
494
|
+
: message;
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* The version's wire ceiling, checked on the compiled bytes before a signer
|
|
498
|
+
* is ever reached.
|
|
499
|
+
*
|
|
500
|
+
* The V1 structural caps ({@link V1_MAX_SIGNATURES} signatures,
|
|
501
|
+
* {@link V1_MAX_ACCOUNTS} accounts, {@link V1_MAX_INSTRUCTIONS} top-level
|
|
502
|
+
* instructions) are enforced by `compileTransaction` itself, so they fail
|
|
503
|
+
* here too — one compile earlier than this check, and equally before
|
|
504
|
+
* signing. Re-implementing them would only risk disagreeing with the codec.
|
|
505
|
+
*/
|
|
506
|
+
function assertWithinSizeLimit(version, size) {
|
|
507
|
+
const limit = version === 1 ? V1_TRANSACTION_SIZE_LIMIT : LEGACY_TRANSACTION_SIZE_LIMIT;
|
|
508
|
+
if (size > limit) {
|
|
509
|
+
throw new Error(`Transaction is ${size} bytes, over the ${limit}-byte limit for version `
|
|
510
|
+
+ `${JSON.stringify(version)}`);
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
/** Measured consumption plus headroom, positive and protocol-bounded. */
|
|
514
|
+
function estimatedComputeUnitLimit(unitsConsumed) {
|
|
515
|
+
const padded = (unitsConsumed * (100n + ESTIMATED_COMPUTE_UNIT_HEADROOM_PERCENT) + 99n) / 100n;
|
|
516
|
+
if (padded < 1n)
|
|
517
|
+
return 1n;
|
|
518
|
+
return padded > BigInt(MAX_COMPUTE_UNIT_LIMIT) ? BigInt(MAX_COMPUTE_UNIT_LIMIT) : padded;
|
|
519
|
+
}
|
|
520
|
+
/** Measured loaded data rounded up to a whole page plus one page of headroom. */
|
|
521
|
+
function estimatedLoadedAccountsDataSize(loadedBytes) {
|
|
522
|
+
const page = BigInt(LOADED_ACCOUNTS_DATA_PAGE_BYTES);
|
|
523
|
+
const padded = ((loadedBytes + page - 1n) / page + 1n) * page;
|
|
524
|
+
const max = BigInt(MAX_LOADED_ACCOUNTS_DATA_SIZE);
|
|
525
|
+
return padded > max ? max : padded;
|
|
526
|
+
}
|
|
527
|
+
async function fetchLatestBlockhash(resolved, commitment, minContextSlot) {
|
|
528
|
+
const value = resolved.kind === 'arete'
|
|
529
|
+
? await resolved.transport.getLatestBlockhash({ commitment, minContextSlot })
|
|
530
|
+
: (await resolved.rpc.getLatestBlockhash({ commitment, minContextSlot }).send()).value;
|
|
531
|
+
return {
|
|
532
|
+
blockhash: value.blockhash,
|
|
533
|
+
lastValidBlockHeight: BigInt(value.lastValidBlockHeight),
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
/**
|
|
537
|
+
* Simulate a transaction carrying placeholder signatures. Verification is
|
|
538
|
+
* off on both backends: nothing on this path has touched a signer.
|
|
539
|
+
*/
|
|
540
|
+
async function simulateUnsigned(resolved, wireTransaction, commitment, minContextSlot) {
|
|
541
|
+
if (resolved.kind === 'arete') {
|
|
542
|
+
const simulation = await resolved.transport.simulateTransaction(wireTransaction, {
|
|
543
|
+
commitment,
|
|
544
|
+
minContextSlot,
|
|
545
|
+
});
|
|
546
|
+
return {
|
|
547
|
+
contextSlot: simulation.contextSlot,
|
|
548
|
+
err: simulation.err ?? undefined,
|
|
549
|
+
logs: simulation.logs ?? undefined,
|
|
550
|
+
unitsConsumed: simulation.unitsConsumed,
|
|
551
|
+
loadedAccountsDataSize: simulation.loadedAccountsDataSize,
|
|
552
|
+
};
|
|
553
|
+
}
|
|
554
|
+
const simulation = await resolved.rpc.simulateTransaction(wireTransaction, { commitment, encoding: 'base64', minContextSlot, sigVerify: false }).send();
|
|
555
|
+
// The loaded-accounts budget is optional upstream and comes back as null
|
|
556
|
+
// when the node did not measure it; `Number(null)` would invent a measured
|
|
557
|
+
// zero and destroy the distinction estimation depends on.
|
|
558
|
+
const { loadedAccountsDataSize } = simulation.value;
|
|
559
|
+
return {
|
|
560
|
+
contextSlot: simulation.context.slot,
|
|
561
|
+
err: simulation.value.err ?? undefined,
|
|
562
|
+
logs: simulation.value.logs ?? undefined,
|
|
563
|
+
unitsConsumed: simulation.value.unitsConsumed == null
|
|
564
|
+
? undefined
|
|
565
|
+
: BigInt(simulation.value.unitsConsumed),
|
|
566
|
+
loadedAccountsDataSize: loadedAccountsDataSize == null
|
|
567
|
+
? undefined
|
|
568
|
+
: BigInt(loadedAccountsDataSize),
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
async function estimateFee(resolved, encodedMessage, commitment, minContextSlot) {
|
|
572
|
+
if (resolved.kind === 'arete') {
|
|
573
|
+
const fee = await resolved.transport.getFeeForMessage(encodedMessage, {
|
|
574
|
+
commitment,
|
|
575
|
+
minContextSlot,
|
|
576
|
+
});
|
|
577
|
+
return {
|
|
578
|
+
feeLamports: fee.feeLamports === null ? undefined : fee.feeLamports,
|
|
579
|
+
contextSlot: fee.contextSlot,
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
const fee = await resolved.rpc
|
|
583
|
+
.getFeeForMessage(encodedMessage, { commitment, minContextSlot })
|
|
584
|
+
.send();
|
|
585
|
+
return {
|
|
586
|
+
feeLamports: fee.value === null ? undefined : fee.value,
|
|
587
|
+
contextSlot: fee.context.slot,
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
/**
|
|
591
|
+
* The V1 message a simulation can actually execute: the caller's own budgets
|
|
592
|
+
* where they gave them, the protocol maxima where they did not.
|
|
593
|
+
*/
|
|
594
|
+
function provisionalV1Resources(resources) {
|
|
595
|
+
return {
|
|
596
|
+
...resources,
|
|
597
|
+
computeUnitLimit: resources.computeUnitLimit ?? BigInt(MAX_COMPUTE_UNIT_LIMIT),
|
|
598
|
+
loadedAccountsDataSizeLimit: resources.loadedAccountsDataSizeLimit ?? BigInt(MAX_LOADED_ACCOUNTS_DATA_SIZE),
|
|
599
|
+
};
|
|
600
|
+
}
|
|
601
|
+
/**
|
|
602
|
+
* Resolve the two budgets a signable V1 message must declare.
|
|
603
|
+
*
|
|
604
|
+
* An unset V1 budget requests the *minimum* rather than a default
|
|
605
|
+
* (SIMD-0385), so a final message missing either could only fail on chain.
|
|
606
|
+
* An explicit caller budget is used verbatim and never raised; a missing one
|
|
607
|
+
* is measured by simulating the provisional message and derived with
|
|
608
|
+
* headroom; and a metric the simulation never reported is refused by name.
|
|
609
|
+
*/
|
|
610
|
+
async function resolveV1Budgets(resolved, compileProvisional, resources, commitment, minContextSlot) {
|
|
611
|
+
if (resources.computeUnitLimit !== undefined
|
|
612
|
+
&& resources.loadedAccountsDataSizeLimit !== undefined) {
|
|
613
|
+
return resources;
|
|
614
|
+
}
|
|
615
|
+
const simulation = await simulateUnsigned(resolved, compileProvisional(provisionalV1Resources(resources)), commitment, minContextSlot);
|
|
616
|
+
if (simulation.err) {
|
|
617
|
+
throw new Error(`Budget estimation simulation reported ${JSON.stringify(simulation.err)}; `
|
|
618
|
+
+ 'nothing was submitted');
|
|
619
|
+
}
|
|
620
|
+
const unestimable = (option, metric) => new Error(`${option} is required for transaction version 1 and could not be estimated: the `
|
|
621
|
+
+ `simulation reported no ${metric}. Pass an explicit ${option}, or use a backend whose `
|
|
622
|
+
+ `simulation reports ${metric}.`);
|
|
623
|
+
let { computeUnitLimit, loadedAccountsDataSizeLimit } = resources;
|
|
624
|
+
if (computeUnitLimit === undefined) {
|
|
625
|
+
if (simulation.unitsConsumed === undefined) {
|
|
626
|
+
throw unestimable('computeUnitLimit', 'unitsConsumed');
|
|
627
|
+
}
|
|
628
|
+
computeUnitLimit = estimatedComputeUnitLimit(simulation.unitsConsumed);
|
|
629
|
+
}
|
|
630
|
+
if (loadedAccountsDataSizeLimit === undefined) {
|
|
631
|
+
if (simulation.loadedAccountsDataSize === undefined) {
|
|
632
|
+
throw unestimable('loadedAccountsDataSizeLimit', 'loadedAccountsDataSize');
|
|
633
|
+
}
|
|
634
|
+
loadedAccountsDataSizeLimit = estimatedLoadedAccountsDataSize(simulation.loadedAccountsDataSize);
|
|
635
|
+
}
|
|
636
|
+
return { ...resources, computeUnitLimit, loadedAccountsDataSizeLimit };
|
|
637
|
+
}
|
|
202
638
|
/**
|
|
203
639
|
* Create a {@link WalletAdapter} from a kit RPC pair and a signer.
|
|
204
640
|
*/
|
|
@@ -212,17 +648,21 @@ function createWalletAdapter(config) {
|
|
|
212
648
|
signerAddresses: [...new Set(signerAddresses)],
|
|
213
649
|
supportedTransactionVersions: CAPABILITY.supportedTransactionVersions,
|
|
214
650
|
async signAndSend(instructions, options, context) {
|
|
215
|
-
// Rejects an explicit
|
|
216
|
-
//
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
651
|
+
// Rejects an unsupported explicit version and any version-bound fee
|
|
652
|
+
// used against the wrong version, before a wallet is ever prompted.
|
|
653
|
+
let plan;
|
|
654
|
+
try {
|
|
655
|
+
plan = sdk.resolveTransactionBuildOptions(options, CAPABILITY);
|
|
656
|
+
assertBuildableInputs(instructions, options, plan.transactionVersion);
|
|
657
|
+
}
|
|
658
|
+
catch (cause) {
|
|
220
659
|
throw new KitTransactionExecutionError({
|
|
221
660
|
status: 'not-submitted',
|
|
222
661
|
phase: 'build',
|
|
223
662
|
cause,
|
|
224
663
|
});
|
|
225
664
|
}
|
|
665
|
+
const version = plan.transactionVersion;
|
|
226
666
|
const sendOptions = options;
|
|
227
667
|
const feePayer = sendOptions?.feePayer ?? signer;
|
|
228
668
|
const commitment = toCommitment(options?.confirmationLevel, fallbackCommitment);
|
|
@@ -251,12 +691,30 @@ function createWalletAdapter(config) {
|
|
|
251
691
|
const attachedSigners = [...requiredSignerAddresses]
|
|
252
692
|
.filter((requiredAddress) => requiredAddress !== feePayer.address)
|
|
253
693
|
.map((requiredAddress) => localSignerMap.get(requiredAddress));
|
|
254
|
-
const latestBlockhash = resolved
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
694
|
+
const latestBlockhash = await fetchLatestBlockhash(resolved, commitment);
|
|
695
|
+
lastValidBlockHeight = latestBlockhash.lastValidBlockHeight;
|
|
696
|
+
const compile = (resources) => planMessage({
|
|
697
|
+
version,
|
|
698
|
+
resources,
|
|
699
|
+
instructions,
|
|
700
|
+
latestBlockhash,
|
|
701
|
+
feePayer,
|
|
702
|
+
attachedSigners,
|
|
703
|
+
});
|
|
704
|
+
// The budgets are resolved before the final message exists, so the
|
|
705
|
+
// configuration that is compiled, sized, preflighted and signed is
|
|
706
|
+
// one configuration. The provisional message is sized too: an
|
|
707
|
+
// oversized payload is a build failure with an exact byte count,
|
|
708
|
+
// not a backend-specific simulation error.
|
|
709
|
+
const encodeSized = (compiled) => {
|
|
710
|
+
assertWithinSizeLimit(version, kit.getTransactionSize(compiled));
|
|
711
|
+
return kit.getBase64EncodedWireTransaction(compiled);
|
|
712
|
+
};
|
|
713
|
+
const resources = version === 1
|
|
714
|
+
? await resolveV1Budgets(resolved, (provisional) => encodeSized(kit.compileTransaction(compile(provisional))), plan.resources, commitment)
|
|
715
|
+
: plan.resources;
|
|
716
|
+
message = compile(resources);
|
|
717
|
+
assertWithinSizeLimit(version, kit.getTransactionSize(kit.compileTransaction(message)));
|
|
260
718
|
}
|
|
261
719
|
catch (cause) {
|
|
262
720
|
throw new KitTransactionExecutionError({
|
|
@@ -269,6 +727,7 @@ function createWalletAdapter(config) {
|
|
|
269
727
|
let signature;
|
|
270
728
|
try {
|
|
271
729
|
signedTransaction = await kit.signTransactionMessageWithSigners(message);
|
|
730
|
+
kit.assertIsTransactionWithBlockhashLifetime(signedTransaction);
|
|
272
731
|
signature = kit.getSignatureFromTransaction(signedTransaction);
|
|
273
732
|
}
|
|
274
733
|
catch (cause) {
|
|
@@ -279,31 +738,45 @@ function createWalletAdapter(config) {
|
|
|
279
738
|
});
|
|
280
739
|
}
|
|
281
740
|
if (resolved.kind === 'arete') {
|
|
282
|
-
|
|
741
|
+
// One deadline over submission *and* confirmation: a relay that
|
|
742
|
+
// takes the transaction and then stalls would otherwise hold the
|
|
743
|
+
// caller forever, because no HTTP client here imposes a request
|
|
744
|
+
// timeout. Expiry on either side is submitted-unknown under the
|
|
745
|
+
// signature these bytes carry — never a rebuild, re-sign or resend.
|
|
746
|
+
const deadline = Date.now() + (sendOptions?.confirmationTimeoutMs ?? 60000);
|
|
283
747
|
try {
|
|
284
|
-
const sent = await resolved.transport.sendTransaction(kit.getBase64EncodedWireTransaction(signedTransaction), { skipPreflight: options?.skipPreflight ?? false, preflightCommitment: commitment });
|
|
285
|
-
|
|
748
|
+
const sent = await withDeadline(deadline, resolved.transport.sendTransaction(kit.getBase64EncodedWireTransaction(signedTransaction), { skipPreflight: options?.skipPreflight ?? false, preflightCommitment: commitment }));
|
|
749
|
+
reportSignatureMismatch(signature, sent.signature);
|
|
286
750
|
}
|
|
287
751
|
catch (cause) {
|
|
752
|
+
if (cause instanceof DeadlineExpiredError) {
|
|
753
|
+
throw new KitTransactionExecutionError({
|
|
754
|
+
status: 'submitted-unknown', phase: 'send', signature,
|
|
755
|
+
cause: new Error('The relay did not acknowledge the submission before the confirmation '
|
|
756
|
+
+ 'deadline; the transaction was dispatched once and may still land'),
|
|
757
|
+
});
|
|
758
|
+
}
|
|
288
759
|
if (cause instanceof sdk.TransactionTransportError && cause.submissionState === 'not_submitted') {
|
|
289
760
|
throw new KitTransactionExecutionError({ status: 'not-submitted', phase: 'send', cause });
|
|
290
761
|
}
|
|
762
|
+
if (cause instanceof sdk.TransactionTransportError) {
|
|
763
|
+
reportSignatureMismatch(signature, cause.signature);
|
|
764
|
+
}
|
|
765
|
+
// The locally derived signature stays authoritative: it is the one
|
|
766
|
+
// these bytes carry, so a relay reporting another identifies some
|
|
767
|
+
// other transaction and cannot be what the caller reconciles.
|
|
291
768
|
throw new KitTransactionExecutionError({
|
|
292
|
-
status: 'submitted-unknown', phase: 'send',
|
|
293
|
-
signature: cause instanceof sdk.TransactionTransportError && cause.signature
|
|
294
|
-
? cause.signature : signature,
|
|
295
|
-
cause,
|
|
769
|
+
status: 'submitted-unknown', phase: 'send', signature, cause,
|
|
296
770
|
});
|
|
297
771
|
}
|
|
298
772
|
try {
|
|
299
|
-
return await pollAreteStatus(resolved.transport,
|
|
773
|
+
return await pollAreteStatus(resolved.transport, signature, commitment, lastValidBlockHeight, deadline, sendOptions);
|
|
300
774
|
}
|
|
301
775
|
catch (cause) {
|
|
302
776
|
if (cause instanceof KitTransactionExecutionError)
|
|
303
777
|
throw cause;
|
|
304
778
|
throw new KitTransactionExecutionError({
|
|
305
|
-
status: 'submitted-unknown', phase: 'confirmation',
|
|
306
|
-
signature: submittedSignature, cause,
|
|
779
|
+
status: 'submitted-unknown', phase: 'confirmation', signature, cause,
|
|
307
780
|
});
|
|
308
781
|
}
|
|
309
782
|
}
|
|
@@ -377,71 +850,75 @@ function createWalletAdapter(config) {
|
|
|
377
850
|
}
|
|
378
851
|
},
|
|
379
852
|
async inspectTransaction(instructions, options, context) {
|
|
380
|
-
sdk.resolveTransactionBuildOptions(options, CAPABILITY);
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
}
|
|
853
|
+
const plan = sdk.resolveTransactionBuildOptions(options, CAPABILITY);
|
|
854
|
+
const version = plan.transactionVersion;
|
|
855
|
+
assertBuildableInputs(instructions, options, version);
|
|
384
856
|
const inspectionOptions = options;
|
|
385
857
|
const commitment = inspectionOptions?.commitment ?? fallbackCommitment;
|
|
386
858
|
const minContextSlot = inspectionOptions?.minContextSlot;
|
|
387
859
|
const resolved = resolveTransport(config.transport, rpc, rpcSubscriptions, context);
|
|
388
|
-
const latestBlockhash = resolved
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
860
|
+
const latestBlockhash = await fetchLatestBlockhash(resolved, commitment, minContextSlot);
|
|
861
|
+
// Inspection is where you discover the budgets to pin, so an omitted
|
|
862
|
+
// V1 ceiling becomes the protocol maximum rather than the SIMD-0385
|
|
863
|
+
// minimum: that provisional message is what the reported metrics
|
|
864
|
+
// describe. Nothing here touches a signer — the fee payer is a bare
|
|
865
|
+
// address and the compiled transaction carries placeholder signatures.
|
|
866
|
+
const resources = version === 1 ? provisionalV1Resources(plan.resources) : plan.resources;
|
|
867
|
+
const message = planMessage({
|
|
868
|
+
version,
|
|
869
|
+
resources,
|
|
870
|
+
instructions,
|
|
871
|
+
latestBlockhash,
|
|
872
|
+
feePayer: kit.createNoopSigner(kit.address(inspectionOptions?.feePayer ?? signer.address)),
|
|
873
|
+
});
|
|
392
874
|
const unsignedTransaction = kit.compileTransaction(message);
|
|
875
|
+
// The same ceiling the send path enforces: a payload that could only
|
|
876
|
+
// be rejected on submission is refused here with its byte count,
|
|
877
|
+
// rather than answered with inspection results or a backend-specific
|
|
878
|
+
// simulation error.
|
|
879
|
+
assertWithinSizeLimit(version, kit.getTransactionSize(unsignedTransaction));
|
|
393
880
|
const wireTransaction = kit.getBase64EncodedWireTransaction(unsignedTransaction);
|
|
394
881
|
const encodedMessage = kit.getBase64Decoder().decode(unsignedTransaction.messageBytes);
|
|
395
|
-
if (resolved.kind === 'arete') {
|
|
396
|
-
const [fee, simulation] = await Promise.all([
|
|
397
|
-
resolved.transport.getFeeForMessage(encodedMessage, { commitment, minContextSlot }),
|
|
398
|
-
resolved.transport.simulateTransaction(wireTransaction, { commitment, minContextSlot }),
|
|
399
|
-
]);
|
|
400
|
-
return {
|
|
401
|
-
feeLamports: fee.feeLamports === null ? undefined : toNumber(fee.feeLamports),
|
|
402
|
-
logs: simulation.logs ?? undefined,
|
|
403
|
-
computeUnitsConsumed: simulation.unitsConsumed === undefined
|
|
404
|
-
? undefined : toNumber(simulation.unitsConsumed),
|
|
405
|
-
contextSlot: toNumber(simulation.contextSlot),
|
|
406
|
-
error: simulation.err ?? undefined,
|
|
407
|
-
loadedAccountsDataSize: simulation.loadedAccountsDataSize === undefined
|
|
408
|
-
? undefined : toNumber(simulation.loadedAccountsDataSize),
|
|
409
|
-
feeContextSlot: toNumber(fee.contextSlot),
|
|
410
|
-
};
|
|
411
|
-
}
|
|
412
882
|
const [fee, simulation] = await Promise.all([
|
|
413
|
-
resolved
|
|
414
|
-
resolved
|
|
415
|
-
commitment,
|
|
416
|
-
encoding: 'base64',
|
|
417
|
-
minContextSlot,
|
|
418
|
-
sigVerify: false,
|
|
419
|
-
}).send(),
|
|
883
|
+
estimateFee(resolved, encodedMessage, commitment, minContextSlot),
|
|
884
|
+
simulateUnsigned(resolved, wireTransaction, commitment, minContextSlot),
|
|
420
885
|
]);
|
|
421
|
-
// The RPC reports the loaded-accounts budget that @solana/kit 2.3 does
|
|
422
|
-
// not yet type. It is optional upstream and comes back as null when the
|
|
423
|
-
// node did not measure it — `Number(null)` would invent a measured zero
|
|
424
|
-
// and destroy the missing-versus-zero distinction budget estimation
|
|
425
|
-
// depends on.
|
|
426
|
-
const { loadedAccountsDataSize: directLoadedAccountsDataSize } = simulation.value;
|
|
427
886
|
return {
|
|
428
|
-
feeLamports: fee.
|
|
429
|
-
logs: simulation.
|
|
430
|
-
computeUnitsConsumed: simulation.
|
|
887
|
+
feeLamports: fee.feeLamports === undefined ? undefined : toNumber(fee.feeLamports),
|
|
888
|
+
logs: simulation.logs === undefined ? undefined : [...simulation.logs],
|
|
889
|
+
computeUnitsConsumed: simulation.unitsConsumed === undefined
|
|
890
|
+
? undefined
|
|
891
|
+
: toNumber(simulation.unitsConsumed),
|
|
892
|
+
contextSlot: toNumber(simulation.contextSlot),
|
|
893
|
+
error: simulation.err ?? undefined,
|
|
894
|
+
loadedAccountsDataSize: simulation.loadedAccountsDataSize === undefined
|
|
431
895
|
? undefined
|
|
432
|
-
: toNumber(simulation.
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
? undefined : Number(directLoadedAccountsDataSize),
|
|
437
|
-
feeContextSlot: toNumber(fee.context.slot),
|
|
896
|
+
: toNumber(simulation.loadedAccountsDataSize),
|
|
897
|
+
feeContextSlot: toNumber(fee.contextSlot),
|
|
898
|
+
transactionVersion: version,
|
|
899
|
+
resources: sdk.toWireResourceOptions(resources),
|
|
438
900
|
};
|
|
439
901
|
},
|
|
440
902
|
};
|
|
441
903
|
}
|
|
442
904
|
|
|
905
|
+
exports.ESTIMATED_COMPUTE_UNIT_HEADROOM_PERCENT = ESTIMATED_COMPUTE_UNIT_HEADROOM_PERCENT;
|
|
443
906
|
exports.KitTransactionExecutionError = KitTransactionExecutionError;
|
|
907
|
+
exports.LEGACY_TRANSACTION_SIZE_LIMIT = LEGACY_TRANSACTION_SIZE_LIMIT;
|
|
908
|
+
exports.LOADED_ACCOUNTS_DATA_PAGE_BYTES = LOADED_ACCOUNTS_DATA_PAGE_BYTES;
|
|
909
|
+
exports.MAX_COMPUTE_UNIT_LIMIT = MAX_COMPUTE_UNIT_LIMIT;
|
|
910
|
+
exports.MAX_LOADED_ACCOUNTS_DATA_SIZE = MAX_LOADED_ACCOUNTS_DATA_SIZE;
|
|
911
|
+
exports.SOLANA_SIGN_AND_SEND_TRANSACTION = SOLANA_SIGN_AND_SEND_TRANSACTION;
|
|
912
|
+
exports.SOLANA_SIGN_TRANSACTION = SOLANA_SIGN_TRANSACTION;
|
|
913
|
+
exports.V1_MAX_ACCOUNTS = V1_MAX_ACCOUNTS;
|
|
914
|
+
exports.V1_MAX_INSTRUCTIONS = V1_MAX_INSTRUCTIONS;
|
|
915
|
+
exports.V1_MAX_SIGNATURES = V1_MAX_SIGNATURES;
|
|
916
|
+
exports.V1_TRANSACTION_SIZE_LIMIT = V1_TRANSACTION_SIZE_LIMIT;
|
|
917
|
+
exports.WalletStandardSignerError = WalletStandardSignerError;
|
|
444
918
|
exports.createWalletAdapter = createWalletAdapter;
|
|
919
|
+
exports.createWalletStandardSigner = createWalletStandardSigner;
|
|
920
|
+
exports.estimatedComputeUnitLimit = estimatedComputeUnitLimit;
|
|
921
|
+
exports.estimatedLoadedAccountsDataSize = estimatedLoadedAccountsDataSize;
|
|
445
922
|
exports.fromAccountRole = fromAccountRole;
|
|
446
923
|
exports.fromKitInstruction = fromKitInstruction;
|
|
447
924
|
exports.toAccountRole = toAccountRole;
|