@@ -22,7 +22,6 @@ import type {
22
22
} from '@wormhole-foundation/sdk-connect' ;
23
23
import {
24
24
createVAA ,
25
- deserializeLayout ,
26
25
toChain ,
27
26
toChainId ,
28
27
} from '@wormhole-foundation/sdk-connect' ;
@@ -36,7 +35,7 @@ import {
36
35
SolanaPlatform ,
37
36
SolanaUnsignedTransaction ,
38
37
} from '@wormhole-foundation/sdk-solana' ;
39
- import { postMessageLayout } from './postMessageLayout.js' ;
38
+ import { deserializePostMessage } from './postMessageLayout.js' ;
40
39
import type { Wormhole as WormholeCoreContract } from './types.js' ;
41
40
import type { BridgeData } from './utils/index.js' ;
42
41
import {
@@ -225,18 +224,36 @@ export class SolanaWormholeCore<N extends Network, C extends SolanaChains>
225
224
coreBridgeAddress : string ,
226
225
transaction : VersionedTransactionResponse | TransactionResponse ,
227
226
) : [ UniversalAddress , bigint ] [ ] {
228
- if ( ! transaction . meta ?. innerInstructions ?. length ) return [ ] ;
227
+ const {
228
+ meta,
229
+ transaction : { message } ,
230
+ } = transaction ;
231
+ if ( ! meta ?. innerInstructions ?. length ) return [ ] ;
232
+
233
+ // Only consider transactions where the core bridge is in static keys
234
+ const accounts = message . staticAccountKeys ;
235
+ if (
236
+ accounts . filter ( ( pk ) => pk . toString ( ) === coreBridgeAddress ) . length === 0
237
+ )
238
+ return [ ] ;
239
+
240
+ // Do we have a sequence in the log?
241
+ const sequence = meta ?. logMessages
242
+ ?. filter ( ( msg ) => msg . startsWith ( SOLANA_SEQ_LOG ) ) ?. [ 0 ]
243
+ ?. replace ( SOLANA_SEQ_LOG , '' ) ;
244
+ if ( ! sequence ) return [ ] ;
229
245
230
- const accounts = transaction . transaction . message . staticAccountKeys ;
231
246
const bridgeIx : CompiledInstruction [ ] = [ ] ;
232
- for ( const inner of transaction . meta ?. innerInstructions ) {
247
+ for ( const inner of meta ?. innerInstructions ) {
233
248
const instructions = inner . instructions ;
234
249
// find the instruction where the programId equals the
235
250
// Wormhole ProgramId and the emitter equals the Token Bridge
236
251
bridgeIx . push (
237
252
...instructions . filter ( ( i ) => {
238
- const programId = accounts [ i . programIdIndex ] ! . toString ( ) ;
239
- return programId === coreBridgeAddress ;
253
+ ! (
254
+ i . programIdIndex in accounts &&
255
+ accounts [ i . programIdIndex ] ! . toString ( ) === coreBridgeAddress
256
+ ) ;
240
257
} ) ,
241
258
) ;
242
259
}
@@ -249,13 +266,6 @@ export class SolanaWormholeCore<N extends Network, C extends SolanaChains>
249
266
const emitter = new SolanaAddress (
250
267
accounts [ ix . accounts [ 2 ] ! ] ! ,
251
268
) . toUniversalAddress ( ) ;
252
-
253
- const sequence = transaction . meta ?. logMessages
254
- ?. filter ( ( msg ) => msg . startsWith ( SOLANA_SEQ_LOG ) ) ?. [ 0 ]
255
- ?. replace ( SOLANA_SEQ_LOG , '' ) ;
256
-
257
- if ( ! sequence ) return null ;
258
-
259
269
return [ emitter , BigInt ( sequence ) ] ;
260
270
} )
261
271
. filter ( ( x ) => x !== null ) as [ UniversalAddress , bigint ] [ ] ;
@@ -297,32 +307,37 @@ export class SolanaWormholeCore<N extends Network, C extends SolanaChains>
297
307
return accounts ;
298
308
}
299
309
300
- private async findBridgeInstructions (
310
+ private async findInstructions (
301
311
accounts : MessageAccountKeys ,
302
312
response : VersionedTransactionResponse ,
303
313
) : Promise < MessageCompiledInstruction [ ] > {
304
- // find the instruction where the programId equals the Wormhole ProgramId
305
- const iix = response !
306
- . meta ! . innerInstructions ! [ 0 ] ! . instructions . filter ( ( i ) => {
307
- const programId = accounts . get ( i . programIdIndex ) ! . toString ( ) ;
308
- const wormholeCore = this . coreBridge . programId . toString ( ) ;
309
- return programId === wormholeCore ;
310
- } )
314
+ const {
315
+ meta,
316
+ transaction : { message } ,
317
+ } = response ;
318
+
319
+ const programId = this . coreBridge . programId ;
320
+
321
+ const iix = meta ! . innerInstructions
322
+ ?. flatMap ( ( ix ) =>
323
+ ix . instructions . filter (
324
+ // find the instructions where the programId equals the Wormhole ProgramId
325
+ ( i ) =>
326
+ programId . toString ( ) === accounts . get ( i . programIdIndex ) ! . toString ( ) ,
327
+ ) ,
328
+ )
311
329
. map ( ( ix ) => {
312
330
// map over inner ixs to put it in the same format as the compiled instructions
313
331
// from the message
314
332
return {
315
333
programIdIndex : ix . programIdIndex ,
316
334
accountKeyIndexes : ix . accounts ,
317
- } as MessageCompiledInstruction ;
318
- } ) ;
335
+ } ;
336
+ } ) as MessageCompiledInstruction [ ] ;
319
337
320
- const cix = response . transaction . message . compiledInstructions . filter (
321
- ( i ) => {
322
- const programId = accounts . get ( i . programIdIndex ) ! . toString ( ) ;
323
- const wormholeCore = this . coreBridge . programId . toString ( ) ;
324
- return programId === wormholeCore ;
325
- } ,
338
+ const cix = message . compiledInstructions . filter (
339
+ ( i ) =>
340
+ programId . toString ( ) === accounts . get ( i . programIdIndex ) ! . toString ( ) ,
326
341
) ;
327
342
328
343
// find the instruction where the programId equals the Wormhole ProgramId
@@ -341,7 +356,7 @@ export class SolanaWormholeCore<N extends Network, C extends SolanaChains>
341
356
sequence,
342
357
nonce,
343
358
payload,
344
- } = deserializeLayout ( postMessageLayout , new Uint8Array ( acctInfo ?. data ! ) ) ;
359
+ } = deserializePostMessage ( new Uint8Array ( acctInfo ?. data ! ) ) ;
345
360
346
361
return createVAA ( 'Uint8Array' , {
347
362
guardianSet : await this . getGuardianSetIndex ( ) ,
@@ -365,28 +380,30 @@ export class SolanaWormholeCore<N extends Network, C extends SolanaChains>
365
380
if ( ! response || ! response . meta || ! response . meta . innerInstructions )
366
381
throw new Error ( 'transaction not found' ) ;
367
382
368
- // The sequence is frequently found in the log, pull from there if we can
369
- const loggedSeqs = SolanaWormholeCore . parseSequenceFromLog (
370
- this . coreBridge . programId . toBase58 ( ) ,
371
- response ,
372
- ) ;
373
- if ( loggedSeqs . length > 0 ) {
374
- const [ emitter , seq ] = loggedSeqs [ 0 ] ! ;
375
- return [
376
- {
377
- chain : this . chain ,
378
- emitter : emitter ,
379
- sequence : seq ,
380
- } ,
381
- ] ;
383
+ try {
384
+ // The sequence is frequently found in the log, pull from there if we can
385
+ const loggedSeqs = SolanaWormholeCore . parseSequenceFromLog (
386
+ this . coreBridge . programId . toBase58 ( ) ,
387
+ response ,
388
+ ) ;
389
+ if ( loggedSeqs . length > 0 ) {
390
+ const [ emitter , seq ] = loggedSeqs [ 0 ] ! ;
391
+ return [
392
+ {
393
+ chain : this . chain ,
394
+ emitter : emitter ,
395
+ sequence : seq ,
396
+ } ,
397
+ ] ;
398
+ }
399
+ } catch {
400
+ // but since the account keys may need to be resolved, it could fail
382
401
}
383
402
384
- // Otherwise we need to get it from the message account
385
403
const accounts = await this . getMessageAccountKeys ( response ) ;
386
- const bridgeInstructions = await this . findBridgeInstructions (
387
- accounts ,
388
- response ,
389
- ) ;
404
+
405
+ // Otherwise we need to get it from the message account
406
+ const bridgeInstructions = await this . findInstructions ( accounts , response ) ;
390
407
391
408
if ( ! bridgeInstructions || bridgeInstructions . length === 0 )
392
409
throw new Error ( 'no bridge messages found' ) ;
@@ -416,10 +433,7 @@ export class SolanaWormholeCore<N extends Network, C extends SolanaChains>
416
433
417
434
// Otherwise we need to get it from the message account
418
435
const accounts = await this . getMessageAccountKeys ( response ) ;
419
- const bridgeInstructions = await this . findBridgeInstructions (
420
- accounts ,
421
- response ,
422
- ) ;
436
+ const bridgeInstructions = await this . findInstructions ( accounts , response ) ;
423
437
424
438
if ( ! bridgeInstructions || bridgeInstructions . length === 0 )
425
439
throw new Error ( 'no bridge messages found' ) ;
0 commit comments