@omegax/protocol-sdk 0.4.3 → 0.5.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/dist/rpc.js CHANGED
@@ -1,5 +1,31 @@
1
- import { Connection, Transaction, } from '@solana/web3.js';
1
+ import { Connection, } from '@solana/web3.js';
2
2
  import { normalizeClaimSimulationFailure } from './claims.js';
3
+ import { decodeSolanaTransaction, serializeSolanaTransaction, } from './transactions.js';
4
+ function shouldRetrySignedSimulationWithoutSigVerify(params) {
5
+ const message = params.error instanceof Error ? params.error.message : String(params.error);
6
+ return (params.sigVerify
7
+ && /invalid arguments/i.test(message));
8
+ }
9
+ async function simulateSignedTransaction(connection, transaction, options) {
10
+ const rpcRequest = connection._rpcRequest;
11
+ if (typeof rpcRequest !== 'function') {
12
+ return await connection.simulateTransaction(transaction, options);
13
+ }
14
+ const unsafe = await rpcRequest.call(connection, 'simulateTransaction', [
15
+ serializeSolanaTransaction(transaction).toString('base64'),
16
+ {
17
+ encoding: 'base64',
18
+ ...options,
19
+ },
20
+ ]);
21
+ if (unsafe?.error) {
22
+ throw new Error(unsafe.error.message ?? 'failed to simulate transaction');
23
+ }
24
+ if (!unsafe?.result?.value) {
25
+ throw new Error('failed to simulate transaction: missing RPC result');
26
+ }
27
+ return unsafe.result;
28
+ }
3
29
  export const OMEGAX_NETWORKS = {
4
30
  devnet: {
5
31
  network: 'devnet',
@@ -73,7 +99,7 @@ export function createRpcClient(connection) {
73
99
  async simulateSignedTx(params) {
74
100
  let tx;
75
101
  try {
76
- tx = Transaction.from(Buffer.from(params.signedTxBase64, 'base64'));
102
+ tx = decodeSolanaTransaction(params.signedTxBase64);
77
103
  }
78
104
  catch (error) {
79
105
  return {
@@ -84,11 +110,46 @@ export function createRpcClient(connection) {
84
110
  failure: normalizeClaimSimulationFailure({ err: error, logs: [] }),
85
111
  };
86
112
  }
87
- const result = await connection.simulateTransaction(tx, {
113
+ const replaceRecentBlockhash = params.replaceRecentBlockhash ?? true;
114
+ const sigVerify = params.sigVerify ?? true;
115
+ const baseOptions = {
88
116
  commitment: params.commitment ?? 'confirmed',
89
- replaceRecentBlockhash: params.replaceRecentBlockhash ?? true,
90
- sigVerify: params.sigVerify ?? true,
91
- });
117
+ replaceRecentBlockhash,
118
+ sigVerify,
119
+ };
120
+ let result;
121
+ try {
122
+ result = await simulateSignedTransaction(connection, tx, baseOptions);
123
+ }
124
+ catch (error) {
125
+ if (!shouldRetrySignedSimulationWithoutSigVerify({
126
+ error,
127
+ sigVerify,
128
+ })) {
129
+ return {
130
+ ok: false,
131
+ logs: [],
132
+ unitsConsumed: null,
133
+ err: error,
134
+ failure: normalizeClaimSimulationFailure({ err: error, logs: [] }),
135
+ };
136
+ }
137
+ try {
138
+ result = await simulateSignedTransaction(connection, tx, {
139
+ ...baseOptions,
140
+ sigVerify: false,
141
+ });
142
+ }
143
+ catch (retryError) {
144
+ return {
145
+ ok: false,
146
+ logs: [],
147
+ unitsConsumed: null,
148
+ err: retryError,
149
+ failure: normalizeClaimSimulationFailure({ err: retryError, logs: [] }),
150
+ };
151
+ }
152
+ }
92
153
  const logs = result.value.logs ?? [];
93
154
  const unitsConsumed = typeof result.value.unitsConsumed === 'number'
94
155
  ? result.value.unitsConsumed
@@ -0,0 +1,11 @@
1
+ import { Transaction, VersionedTransaction } from '@solana/web3.js';
2
+ export type SolanaTransaction = Transaction | VersionedTransaction;
3
+ export declare function decodeSolanaTransaction(input: string | Uint8Array | Buffer): SolanaTransaction;
4
+ export declare function serializeSolanaTransaction(transaction: SolanaTransaction): Buffer;
5
+ export declare function serializeSolanaTransactionBase64(transaction: SolanaTransaction): string;
6
+ export declare function solanaTransactionMessageBytes(transaction: SolanaTransaction): Uint8Array;
7
+ export declare function solanaTransactionIntentMessageBytes(transaction: SolanaTransaction): Uint8Array;
8
+ export declare function solanaTransactionMessageBase64(input: SolanaTransaction | string | Uint8Array | Buffer): string;
9
+ export declare function solanaTransactionRequiredSigner(transaction: SolanaTransaction): string | null;
10
+ export declare function solanaTransactionFirstSignature(transaction: SolanaTransaction): string | null;
11
+ export declare function solanaTransactionSignerSignature(transaction: SolanaTransaction, signer: string): Uint8Array | null;
@@ -0,0 +1,121 @@
1
+ import bs58 from 'bs58';
2
+ import { Transaction, VersionedTransaction, } from '@solana/web3.js';
3
+ function decodeShortVecLength(bytes, offset = 0) {
4
+ let length = 0;
5
+ let size = 0;
6
+ let cursor = offset;
7
+ while (cursor < bytes.length) {
8
+ const value = bytes[cursor] ?? 0;
9
+ length |= (value & 0x7f) << (size * 7);
10
+ size += 1;
11
+ cursor += 1;
12
+ if ((value & 0x80) === 0) {
13
+ return { length, bytesRead: size };
14
+ }
15
+ }
16
+ throw new Error('invalid shortvec length');
17
+ }
18
+ function versionedStaticAccountKeys(transaction) {
19
+ const message = transaction.message;
20
+ return (message?.staticAccountKeys ??
21
+ message?.getAccountKeys?.().staticAccountKeys ??
22
+ []);
23
+ }
24
+ function signatureIsPresent(signature) {
25
+ if (!signature || signature.length === 0)
26
+ return false;
27
+ return signature.some((value) => value !== 0);
28
+ }
29
+ export function decodeSolanaTransaction(input) {
30
+ const bytes = typeof input === 'string' ? Buffer.from(input, 'base64') : Buffer.from(input);
31
+ const { length: signatureCount, bytesRead } = decodeShortVecLength(bytes);
32
+ const messageOffset = bytesRead + signatureCount * 64;
33
+ if (messageOffset >= bytes.length) {
34
+ throw new Error('invalid serialized transaction');
35
+ }
36
+ const messagePrefix = bytes[messageOffset] ?? 0;
37
+ if ((messagePrefix & 0x80) !== 0) {
38
+ return VersionedTransaction.deserialize(bytes);
39
+ }
40
+ return Transaction.from(bytes);
41
+ }
42
+ export function serializeSolanaTransaction(transaction) {
43
+ if (transaction instanceof Transaction) {
44
+ return transaction.serialize({
45
+ requireAllSignatures: false,
46
+ verifySignatures: false,
47
+ });
48
+ }
49
+ return Buffer.from(transaction.serialize());
50
+ }
51
+ export function serializeSolanaTransactionBase64(transaction) {
52
+ return serializeSolanaTransaction(transaction).toString('base64');
53
+ }
54
+ export function solanaTransactionMessageBytes(transaction) {
55
+ if (transaction instanceof Transaction) {
56
+ return transaction.serializeMessage();
57
+ }
58
+ return transaction.message.serialize();
59
+ }
60
+ function normalizeSolanaMessageBytesIgnoringRecentBlockhash(messageBytes) {
61
+ const normalized = Uint8Array.from(messageBytes);
62
+ const messagePrefix = normalized[0] ?? 0;
63
+ const isVersioned = (messagePrefix & 0x80) !== 0;
64
+ let cursor = isVersioned ? 1 : 0;
65
+ cursor += 3;
66
+ const { length: accountKeyCount, bytesRead } = decodeShortVecLength(normalized, cursor);
67
+ cursor += bytesRead + accountKeyCount * 32;
68
+ if (cursor + 32 > normalized.length) {
69
+ throw new Error('invalid serialized transaction message');
70
+ }
71
+ normalized.fill(0, cursor, cursor + 32);
72
+ return normalized;
73
+ }
74
+ export function solanaTransactionIntentMessageBytes(transaction) {
75
+ return normalizeSolanaMessageBytesIgnoringRecentBlockhash(solanaTransactionMessageBytes(transaction));
76
+ }
77
+ export function solanaTransactionMessageBase64(input) {
78
+ const transaction = typeof input === 'string' || input instanceof Uint8Array || Buffer.isBuffer(input)
79
+ ? decodeSolanaTransaction(input)
80
+ : input;
81
+ return Buffer.from(solanaTransactionMessageBytes(transaction)).toString('base64');
82
+ }
83
+ export function solanaTransactionRequiredSigner(transaction) {
84
+ if (transaction instanceof Transaction) {
85
+ return transaction.feePayer?.toBase58() ?? null;
86
+ }
87
+ const accountKeys = versionedStaticAccountKeys(transaction);
88
+ return accountKeys[0]?.toBase58() ?? null;
89
+ }
90
+ export function solanaTransactionFirstSignature(transaction) {
91
+ if (transaction instanceof Transaction) {
92
+ if (transaction.signatures.length === 0)
93
+ return null;
94
+ const first = transaction.signatures[0];
95
+ if (!signatureIsPresent(first?.signature))
96
+ return null;
97
+ return bs58.encode(first.signature);
98
+ }
99
+ const first = transaction.signatures[0];
100
+ if (!signatureIsPresent(first))
101
+ return null;
102
+ return bs58.encode(first);
103
+ }
104
+ export function solanaTransactionSignerSignature(transaction, signer) {
105
+ if (transaction instanceof Transaction) {
106
+ const entry = transaction.signatures.find((candidate) => candidate.publicKey.toBase58() === signer);
107
+ return signatureIsPresent(entry?.signature) ? entry?.signature : null;
108
+ }
109
+ const accountKeys = versionedStaticAccountKeys(transaction);
110
+ const signerIndex = accountKeys.findIndex((candidate) => candidate.toBase58() === signer);
111
+ if (signerIndex < 0)
112
+ return null;
113
+ const header = transaction.message
114
+ .header;
115
+ const requiredSignerCount = header?.numRequiredSignatures ?? 0;
116
+ if (signerIndex >= requiredSignerCount) {
117
+ return null;
118
+ }
119
+ const signature = transaction.signatures[signerIndex];
120
+ return signatureIsPresent(signature) ? signature : null;
121
+ }