diff --git a/platforms/solana/protocols/core/src/core.ts b/platforms/solana/protocols/core/src/core.ts index 8cc8600a64..a5350c16b3 100644 --- a/platforms/solana/protocols/core/src/core.ts +++ b/platforms/solana/protocols/core/src/core.ts @@ -34,8 +34,10 @@ import { createPostVaaInstruction, createReadOnlyWormholeProgramInterface, createVerifySignaturesInstructions, + createBridgeFeeTransferInstruction, derivePostedVaaKey, getWormholeBridgeData, + BridgeData, } from './utils'; const SOLANA_SEQ_LOG = 'Program log: Sequence: '; @@ -46,6 +48,7 @@ export class SolanaWormholeCore readonly chainId: ChainId; readonly coreBridge: Program; readonly address: string; + protected bridgeData?: BridgeData; constructor( readonly network: N, @@ -79,6 +82,7 @@ export class SolanaWormholeCore throw new Error( `Network mismatch for chain ${chain}: ${conf.network} != ${network}`, ); + return new SolanaWormholeCore( network as N, chain, @@ -88,11 +92,14 @@ export class SolanaWormholeCore } async getMessageFee(): Promise { - const bd = await getWormholeBridgeData( - this.connection, - this.coreBridge.programId, - ); - return bd.config.fee; + // cache lookups since this should not change frequently + if (!this.bridgeData) + this.bridgeData = await getWormholeBridgeData( + this.connection, + this.coreBridge.programId, + ); + + return this.bridgeData.config.fee; } async *publishMessage( @@ -113,11 +120,18 @@ export class SolanaWormholeCore consistencyLevel, ); + const fee = await this.getMessageFee(); + const feeTransferIx = createBridgeFeeTransferInstruction( + this.coreBridge.programId, + payer, + fee, + ); + const { blockhash } = await SolanaPlatform.latestBlock(this.connection); const transaction = new Transaction(); transaction.recentBlockhash = blockhash; transaction.feePayer = payer; - transaction.add(postMsgIx); + transaction.add(feeTransferIx, postMsgIx); transaction.partialSign(messageAccount); yield this.createUnsignedTx(transaction, 'Core.PublishMessage'); diff --git a/platforms/solana/protocols/core/src/utils/instructions/feeTransfer.ts b/platforms/solana/protocols/core/src/utils/instructions/feeTransfer.ts index ae0945c7e5..5257f5f152 100644 --- a/platforms/solana/protocols/core/src/utils/instructions/feeTransfer.ts +++ b/platforms/solana/protocols/core/src/utils/instructions/feeTransfer.ts @@ -1,24 +1,16 @@ import { - Commitment, - Connection, PublicKey, PublicKeyInitData, SystemProgram, TransactionInstruction, } from '@solana/web3.js'; -import { deriveFeeCollectorKey, getWormholeBridgeData } from '../accounts'; +import { deriveFeeCollectorKey } from '../accounts'; -export async function createBridgeFeeTransferInstruction( - connection: Connection, +export function createBridgeFeeTransferInstruction( wormholeProgramId: PublicKeyInitData, payer: PublicKeyInitData, - commitment?: Commitment, -): Promise { - const fee = await getWormholeBridgeData( - connection, - wormholeProgramId, - commitment, - ).then((data) => data.config.fee); + fee: bigint, +): TransactionInstruction { return SystemProgram.transfer({ fromPubkey: new PublicKey(payer), toPubkey: deriveFeeCollectorKey(wormholeProgramId), diff --git a/platforms/solana/protocols/tokenBridge/src/tokenBridge.ts b/platforms/solana/protocols/tokenBridge/src/tokenBridge.ts index e876389543..2744b2bbd2 100644 --- a/platforms/solana/protocols/tokenBridge/src/tokenBridge.ts +++ b/platforms/solana/protocols/tokenBridge/src/tokenBridge.ts @@ -216,11 +216,13 @@ export class SolanaTokenBridge // TODO: createNonce().readUInt32LE(0); const nonce = 0; - const transferIx = await coreUtils.createBridgeFeeTransferInstruction( - this.connection, + const fee = await this.coreBridge.getMessageFee(); + const transferIx = coreUtils.createBridgeFeeTransferInstruction( this.coreBridge.address, - senderAddress, + payer, + fee, ); + const messageKey = Keypair.generate(); const attestIx = createAttestTokenInstruction( this.connection, diff --git a/platforms/solana/src/platform.ts b/platforms/solana/src/platform.ts index c65c187e02..c06f62f336 100644 --- a/platforms/solana/src/platform.ts +++ b/platforms/solana/src/platform.ts @@ -166,10 +166,9 @@ export class SolanaPlatform extends PlatformContext< // recoverable. Currently handles: // - Blockhash not found (blockhash too new for the node we submitted to) // - Not enough bytes (storage account not seen yet) - private static async sendWithRetry( rpc: Connection, - stxns: SignedTx, + stxn: SignedTx, opts: SendOptions, retries: number = 3, ): Promise { @@ -177,7 +176,7 @@ export class SolanaPlatform extends PlatformContext< if (!retries) throw new Error('Too many retries'); try { - const txid = await rpc.sendRawTransaction(stxns.tx, opts); + const txid = await rpc.sendRawTransaction(stxn, opts); return txid; } catch (e) { retries -= 1; @@ -195,7 +194,7 @@ export class SolanaPlatform extends PlatformContext< // Blockhash not found _yet_ if (emsg.includes('Blockhash not found')) - return this.sendWithRetry(rpc, stxns, opts, retries); + return this.sendWithRetry(rpc, stxn, opts, retries); // Find the log message with the error details const loggedErr = e.logs.find((log) => @@ -204,7 +203,9 @@ export class SolanaPlatform extends PlatformContext< // Probably caused by storage account not seen yet if (loggedErr && loggedErr.includes('Not enough bytes')) - return this.sendWithRetry(rpc, stxns, opts, retries); + return this.sendWithRetry(rpc, stxn, opts, retries); + + throw e; } }