@@ -3,11 +3,17 @@ import {
3
3
Message ,
4
4
MessageCompiledInstruction ,
5
5
MessageV0 ,
6
+ VersionedBlockResponse ,
7
+ SolanaJSONRPCError ,
8
+ PublicKey ,
9
+ PublicKeyInitData ,
6
10
} from '@solana/web3.js' ;
7
11
import { decode } from 'bs58' ;
8
12
import { Connection } from '@solana/web3.js' ;
9
13
import { RPCS_BY_CHAIN } from '@certusone/wormhole-sdk/lib/cjs/relayer' ;
10
14
import { CONTRACTS } from '@certusone/wormhole-sdk' ;
15
+ import { encoding } from '@wormhole-foundation/sdk-base' ;
16
+ import { BN } from '@coral-xyz/anchor' ;
11
17
12
18
export const isLegacyMessage = ( message : Message | MessageV0 ) : message is Message => {
13
19
return message . version === 'legacy' ;
@@ -60,3 +66,81 @@ export async function convertSolanaTxToAccts(txHash: string): Promise<string[]>
60
66
}
61
67
return accounts ;
62
68
}
69
+
70
+ export const findNextValidBlock = async (
71
+ connection : Connection ,
72
+ slot : number ,
73
+ next : number ,
74
+ retries : number
75
+ ) : Promise < VersionedBlockResponse > => {
76
+ // identify block range by fetching signatures of the first and last transactions
77
+ // getSignaturesForAddress walks backwards so fromSignature occurs after toSignature
78
+ if ( retries === 0 ) throw new Error ( `No block found after exhausting retries` ) ;
79
+
80
+ let block : VersionedBlockResponse | null = null ;
81
+ try {
82
+ block = await connection . getBlock ( slot , { maxSupportedTransactionVersion : 0 } ) ;
83
+ } catch ( e ) {
84
+ if ( e instanceof SolanaJSONRPCError && ( e . code === - 32007 || e . code === - 32009 ) ) {
85
+ // failed to get confirmed block: slot was skipped or missing in long-term storage
86
+ return findNextValidBlock ( connection , slot + next , next , retries - 1 ) ;
87
+ } else {
88
+ throw e ;
89
+ }
90
+ }
91
+
92
+ if ( ! block || ! block . blockTime || block . transactions . length === 0 ) {
93
+ return findNextValidBlock ( connection , slot + next , next , retries - 1 ) ;
94
+ }
95
+
96
+ return block ;
97
+ } ;
98
+
99
+ export const findFromSignatureAndToSignature = async (
100
+ connection : Connection ,
101
+ fromSlot : number ,
102
+ toSlot : number ,
103
+ retries = 5
104
+ ) => {
105
+ let toBlock : VersionedBlockResponse ;
106
+ let fromBlock : VersionedBlockResponse ;
107
+
108
+ try {
109
+ toBlock = await findNextValidBlock ( connection , toSlot + 1 , - 1 , retries ) ;
110
+ fromBlock = await findNextValidBlock ( connection , fromSlot - 1 , 1 , retries ) ;
111
+ } catch ( e ) {
112
+ throw new Error ( 'solana: invalid block range: ' + ( e as Error ) . message ) ;
113
+ }
114
+
115
+ const fromSignature = toBlock . transactions [ 0 ] . transaction . signatures [ 0 ] ;
116
+ const toSignature =
117
+ fromBlock . transactions [ fromBlock . transactions . length - 1 ] . transaction . signatures [ 0 ] ;
118
+
119
+ return { fromSignature, toSignature, toBlock } ;
120
+ } ;
121
+
122
+ // copied from https://github.com/wormhole-foundation/example-native-token-transfers/blob/main/solana/ts/sdk/utils.ts#L38-L52
123
+ export const U64 = {
124
+ MAX : new BN ( ( 2n ** 64n - 1n ) . toString ( ) ) ,
125
+ to : ( amount : number , unit : number ) => {
126
+ const ret = new BN ( Math . round ( amount * unit ) ) ;
127
+
128
+ if ( ret . isNeg ( ) ) throw new Error ( 'Value negative' ) ;
129
+
130
+ if ( ret . bitLength ( ) > 64 ) throw new Error ( 'Value too large' ) ;
131
+
132
+ return ret ;
133
+ } ,
134
+ from : ( amount : BN , unit : number ) => amount . toNumber ( ) / unit ,
135
+ } ;
136
+
137
+ // copied from https://github.com/wormhole-foundation/example-native-token-transfers/blob/main/solana/ts/sdk/utils.ts#L55-L56
138
+ type Seed = Uint8Array | string ;
139
+ export function derivePda ( seeds : Seed | readonly Seed [ ] , programId : PublicKeyInitData ) {
140
+ const toBytes = ( s : string | Uint8Array ) =>
141
+ typeof s === 'string' ? encoding . bytes . encode ( s ) : s ;
142
+ return PublicKey . findProgramAddressSync (
143
+ Array . isArray ( seeds ) ? seeds . map ( toBytes ) : [ toBytes ( seeds as Seed ) ] ,
144
+ new PublicKey ( programId )
145
+ ) [ 0 ] ;
146
+ }
0 commit comments