1
1
import { BorshEventCoder , Idl , utils } from "@coral-xyz/anchor" ;
2
2
import web3 , {
3
3
Address ,
4
+ AddressesByLookupTableAddress ,
5
+ appendTransactionMessageInstruction ,
6
+ appendTransactionMessageInstructions ,
4
7
Commitment ,
8
+ compressTransactionMessageUsingAddressLookupTables as compressTxWithAlt ,
9
+ getSignatureFromTransaction ,
5
10
GetSignaturesForAddressApi ,
6
11
GetTransactionApi ,
12
+ IInstruction ,
13
+ KeyPairSigner ,
14
+ pipe ,
15
+ Rpc ,
16
+ RpcSubscriptions ,
7
17
RpcTransport ,
18
+ sendAndConfirmTransactionFactory ,
8
19
Signature ,
20
+ SignatureNotificationsApi ,
21
+ signTransactionMessageWithSigners ,
22
+ SlotNotificationsApi ,
23
+ SolanaRpcApiFromTransport ,
9
24
} from "@solana/kit" ;
10
25
26
+ import {
27
+ fetchAddressLookupTable ,
28
+ findAddressLookupTablePda ,
29
+ getCreateLookupTableInstructionAsync ,
30
+ getExtendLookupTableInstruction ,
31
+ } from "@solana-program/address-lookup-table" ;
32
+ import { createDefaultTransaction , signAndSendTransaction } from "../../../test/svm/utils" ;
33
+
11
34
type GetTransactionReturnType = ReturnType < GetTransactionApi [ "getTransaction" ] > ;
12
35
13
36
type GetSignaturesForAddressConfig = Parameters < GetSignaturesForAddressApi [ "getSignaturesForAddress" ] > [ 1 ] ;
14
37
15
38
type GetSignaturesForAddressTransaction = ReturnType < GetSignaturesForAddressApi [ "getSignaturesForAddress" ] > [ number ] ;
16
39
40
+ export type RpcClient = {
41
+ rpc : Rpc < SolanaRpcApiFromTransport < RpcTransport > > ;
42
+ rpcSubscriptions : RpcSubscriptions < SignatureNotificationsApi & SlotNotificationsApi > ;
43
+ } ;
44
+
17
45
/**
18
46
* Reads all events for a specific program.
19
47
*/
20
48
export async function readProgramEvents (
21
- rpc : web3 . Rpc < web3 . SolanaRpcApiFromTransport < RpcTransport > > ,
49
+ rpc : RpcClient ,
22
50
program : Address ,
23
51
anchorIdl : Idl ,
24
52
finality : Commitment = "confirmed" ,
@@ -45,14 +73,14 @@ export async function readProgramEvents(
45
73
}
46
74
47
75
async function searchSignaturesUntilLimit (
48
- rpc : web3 . Rpc < web3 . SolanaRpcApiFromTransport < RpcTransport > > ,
76
+ client : RpcClient ,
49
77
program : Address ,
50
78
options : GetSignaturesForAddressConfig = { limit : 1000 }
51
79
) : Promise < GetSignaturesForAddressTransaction [ ] > {
52
80
const allSignatures : GetSignaturesForAddressTransaction [ ] = [ ] ;
53
81
// Fetch all signatures in sequential batches
54
82
while ( true ) {
55
- const signatures = await rpc . getSignaturesForAddress ( program , options ) . send ( ) ;
83
+ const signatures = await client . rpc . getSignaturesForAddress ( program , options ) . send ( ) ;
56
84
allSignatures . push ( ...signatures ) ;
57
85
58
86
// Update options for the next batch. Set before to the last fetched signature.
@@ -69,13 +97,15 @@ async function searchSignaturesUntilLimit(
69
97
* Reads events from a transaction.
70
98
*/
71
99
export async function readEvents (
72
- rpc : web3 . Rpc < web3 . SolanaRpcApiFromTransport < RpcTransport > > ,
100
+ client : RpcClient ,
73
101
txSignature : Signature ,
74
102
programId : Address ,
75
103
programIdl : Idl ,
76
104
commitment : Commitment = "confirmed"
77
105
) {
78
- const txResult = await rpc . getTransaction ( txSignature , { commitment, maxSupportedTransactionVersion : 0 } ) . send ( ) ;
106
+ const txResult = await client . rpc
107
+ . getTransaction ( txSignature , { commitment, maxSupportedTransactionVersion : 0 } )
108
+ . send ( ) ;
79
109
80
110
if ( txResult === null ) return [ ] ;
81
111
@@ -132,16 +162,89 @@ async function processEventFromTx(
132
162
* For a given fillStatusPDa & associated spokePool ProgramID, return the fill event.
133
163
*/
134
164
export async function readFillEventFromFillStatusPda (
135
- rpc : web3 . Rpc < web3 . SolanaRpcApiFromTransport < RpcTransport > > ,
165
+ client : RpcClient ,
136
166
fillStatusPda : Address ,
137
167
programId : Address ,
138
168
programIdl : Idl
139
169
) : Promise < { event : any ; slot : number } > {
140
- const signatures = await searchSignaturesUntilLimit ( rpc , fillStatusPda ) ;
170
+ const signatures = await searchSignaturesUntilLimit ( client , fillStatusPda ) ;
141
171
if ( signatures . length === 0 ) return { event : null , slot : 0 } ;
142
172
143
173
// The first signature will always be PDA creation, and therefore CPI event carrying signature. Any older signatures
144
174
// will therefore be either spam or PDA closure signatures and can be ignored when looking for the fill event.
145
- const events = await readEvents ( rpc , signatures [ signatures . length - 1 ] . signature , programId , programIdl ) ;
175
+ const events = await readEvents ( client , signatures [ signatures . length - 1 ] . signature , programId , programIdl ) ;
146
176
return { event : events [ 0 ] , slot : Number ( signatures [ signatures . length - 1 ] . slot ) } ;
147
177
}
178
+
179
+ export async function createAlt ( client : RpcClient , authority : KeyPairSigner ) : Promise < Address > {
180
+ const recentSlot = await client . rpc . getSlot ( { commitment : "finalized" } ) . send ( ) ;
181
+
182
+ const [ alt ] = await findAddressLookupTablePda ( {
183
+ authority : authority . address ,
184
+ recentSlot,
185
+ } ) ;
186
+
187
+ const createAltIx = await getCreateLookupTableInstructionAsync ( {
188
+ authority,
189
+ recentSlot,
190
+ } ) ;
191
+
192
+ await pipe (
193
+ await createDefaultTransaction ( client , authority ) ,
194
+ ( tx ) => appendTransactionMessageInstruction ( createAltIx , tx ) ,
195
+ ( tx ) => signAndSendTransaction ( client , tx )
196
+ ) ;
197
+
198
+ return alt ;
199
+ }
200
+
201
+ export async function extendAlt ( client : RpcClient , authority : KeyPairSigner , alt : Address , addresses : Address [ ] ) {
202
+ const extendAltIx = getExtendLookupTableInstruction ( {
203
+ address : alt ,
204
+ authority,
205
+ payer : authority ,
206
+ addresses,
207
+ } ) ;
208
+
209
+ await pipe (
210
+ await createDefaultTransaction ( client , authority ) ,
211
+ ( tx ) => appendTransactionMessageInstruction ( extendAltIx , tx ) ,
212
+ ( tx ) => signAndSendTransaction ( client , tx )
213
+ ) ;
214
+
215
+ const altAccount = await fetchAddressLookupTable ( client . rpc , alt ) ;
216
+
217
+ const addressesByLookupTableAddress : AddressesByLookupTableAddress = { } ;
218
+ addressesByLookupTableAddress [ alt ] = altAccount . data . addresses ;
219
+
220
+ // Delay a second here to let lookup table warm up
221
+ await sleep ( 1000 ) ;
222
+
223
+ return addressesByLookupTableAddress ;
224
+ }
225
+
226
+ async function sleep ( ms : number ) {
227
+ return new Promise ( ( resolve ) => setTimeout ( resolve , ms ) ) ;
228
+ }
229
+
230
+ export async function sendTransactionWithAlt (
231
+ client : RpcClient ,
232
+ payer : KeyPairSigner ,
233
+ instructions : IInstruction [ ] ,
234
+ addressesByLookupTableAddress : AddressesByLookupTableAddress
235
+ ) {
236
+ return pipe (
237
+ await createDefaultTransaction ( client , payer ) ,
238
+ ( tx ) => appendTransactionMessageInstructions ( instructions , tx ) ,
239
+ ( tx ) => compressTxWithAlt ( tx , addressesByLookupTableAddress ) ,
240
+ ( tx ) => signTransactionMessageWithSigners ( tx ) ,
241
+ async ( tx ) => {
242
+ const signedTx = await tx ;
243
+ await sendAndConfirmTransactionFactory ( client ) ( signedTx , {
244
+ commitment : "confirmed" ,
245
+ skipPreflight : false ,
246
+ } ) ;
247
+ return getSignatureFromTransaction ( signedTx ) ;
248
+ }
249
+ ) ;
250
+ }
0 commit comments