-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathtransaction.ts
More file actions
246 lines (224 loc) · 6.82 KB
/
transaction.ts
File metadata and controls
246 lines (224 loc) · 6.82 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
import { WasmTransaction } from "./wasm/wasm_solana.js";
import { Pubkey } from "./pubkey.js";
/**
* Account metadata for an instruction
*/
export interface AccountMeta {
/** The account public key as a base58 string */
pubkey: string;
/** Whether this account is a signer */
isSigner: boolean;
/** Whether this account is writable */
isWritable: boolean;
}
/**
* A decoded Solana instruction
*/
export interface Instruction {
/** The program ID (base58 string) that will execute this instruction */
programId: string;
/** The accounts required by this instruction */
accounts: AccountMeta[];
/** The instruction data */
data: Uint8Array;
}
/**
* Solana Transaction wrapper for low-level deserialization and inspection.
*
* This class provides low-level access to transaction structure.
* For high-level semantic parsing with decoded instructions, use `parseTransaction()` instead.
*
* @example
* ```typescript
* import { Transaction, parseTransaction } from '@bitgo/wasm-solana';
*
* // Low-level access:
* const tx = Transaction.fromBytes(txBytes);
* console.log(tx.feePayer);
*
* // High-level parsing (preferred):
* const parsed = parseTransaction(txBytes);
* console.log(parsed.instructionsData); // Decoded instruction types
* ```
*/
export class Transaction {
private constructor(private _wasm: WasmTransaction) {}
/**
* Deserialize a transaction from raw bytes
* @param bytes - The raw transaction bytes
* @returns A Transaction instance
*/
static fromBytes(bytes: Uint8Array): Transaction {
const wasm = WasmTransaction.from_bytes(bytes);
return new Transaction(wasm);
}
/**
* Create a Transaction from a WasmTransaction instance.
* @internal Used by builder functions
*/
static fromWasm(wasm: WasmTransaction): Transaction {
return new Transaction(wasm);
}
/**
* Get the fee payer address as a base58 string
* Returns null if there are no account keys (shouldn't happen for valid transactions)
*/
get feePayer(): string | null {
return this._wasm.fee_payer ?? null;
}
/**
* Get the recent blockhash as a base58 string
*/
get recentBlockhash(): string {
return this._wasm.recent_blockhash;
}
/**
* Get the number of signatures in the transaction
*/
get numSignatures(): number {
return this._wasm.num_signatures;
}
/**
* Get the transaction ID (first signature as base58).
*
* For Solana, the transaction ID is the first signature.
* Returns `undefined` if the transaction is unsigned (no signatures or all-zeros signature).
*
* @example
* ```typescript
* const tx = Transaction.fromBytes(txBytes);
* tx.addSignature(pubkey, signature);
* console.log(tx.id); // Base58 encoded signature
* ```
*/
get id(): string | undefined {
return this._wasm.id;
}
/**
* Get the signable message payload (what gets signed)
* This is the serialized message that signers sign
* @returns The message bytes
*/
signablePayload(): Uint8Array {
return this._wasm.signable_payload();
}
/**
* Serialize the message portion of the transaction.
* Alias for signablePayload() - provides compatibility with @solana/web3.js API.
* @returns The serialized message bytes
*/
serializeMessage(): Uint8Array {
return this.signablePayload();
}
/**
* Serialize the transaction to bytes
* @returns The serialized transaction bytes
*/
toBytes(): Uint8Array {
return this._wasm.to_bytes();
}
/**
* Serialize to network broadcast format.
* @returns The transaction as bytes ready for broadcast
*/
toBroadcastFormat(): Uint8Array {
return this.toBytes();
}
/**
* Get all account keys as Pubkey instances
* @returns Array of account public keys
*/
accountKeys(): Pubkey[] {
const keys = Array.from(this._wasm.account_keys()) as string[];
return keys.map((k) => Pubkey.fromBase58(k));
}
/**
* Get all signatures as byte arrays.
* Provides compatibility with @solana/web3.js Transaction.signatures API.
* @returns Array of signature byte arrays
*/
get signatures(): Uint8Array[] {
return Array.from(this._wasm.signatures()) as Uint8Array[];
}
/**
* Get all signatures as byte arrays (method form).
* Alias for the `signatures` property getter.
* @returns Array of signature byte arrays
*/
getSignatures(): Uint8Array[] {
return this.signatures;
}
/**
* Get all instructions in the transaction.
* Returns an array with programId, accounts, and data for each instruction.
*
* Note: This is a getter property to provide compatibility with code
* expecting @solana/web3.js Transaction.instructions API. If you need
* to call this as a method, use `getInstructions()` instead.
*/
get instructions(): Instruction[] {
const rawInstructions = this._wasm.instructions();
return Array.from(rawInstructions) as Instruction[];
}
/**
* Get all instructions in the transaction (method form).
* Alias for the `instructions` property getter.
* @returns Array of instructions with programId, accounts, and data
*/
getInstructions(): Instruction[] {
return this.instructions;
}
/**
* Add a signature for a given public key.
*
* The pubkey must be one of the required signers in the transaction.
* The signature must be exactly 64 bytes (Ed25519 signature).
*
* @param pubkey - The public key as a base58 string
* @param signature - The 64-byte signature as Uint8Array
* @throws Error if pubkey is not a signer or signature is invalid
*
* @example
* ```typescript
* // Add a pre-computed signature (e.g., from TSS)
* tx.addSignature(signerPubkey, signatureBytes);
*
* // Serialize and broadcast
* const signedTxBytes = tx.toBytes();
* ```
*/
addSignature(pubkey: string, signature: Uint8Array): void {
this._wasm.add_signature(pubkey, signature);
}
/**
* Get the signer index for a public key.
*
* Returns the index in the signatures array where this pubkey's
* signature should be placed, or null if the pubkey is not a signer.
*
* @param pubkey - The public key as a base58 string
* @returns The signer index, or null if not a signer
*/
signerIndex(pubkey: string): number | null {
const idx = this._wasm.signer_index(pubkey);
return idx ?? null;
}
/**
* Sign this transaction with a base58-encoded Ed25519 secret key.
*
* Derives the public key from the secret, signs the transaction message,
* and places the signature at the correct signer index.
*
* @param secretKeyBase58 - The Ed25519 secret key (32-byte seed) as base58
*/
signWithSecretKey(secretKeyBase58: string): void {
this._wasm.sign_with_secret_key(secretKeyBase58);
}
/**
* Get the underlying WASM instance (internal use only)
* @internal
*/
get wasm(): WasmTransaction {
return this._wasm;
}
}