Skip to content

Commit

Permalink
update solana to pass back all signers involved and require the sol s…
Browse files Browse the repository at this point in the history
…igner set the recent blockhash
  • Loading branch information
barnjamin committed Jan 3, 2024
1 parent ebf10c2 commit 44f2b7c
Show file tree
Hide file tree
Showing 10 changed files with 195 additions and 181 deletions.
12 changes: 4 additions & 8 deletions platforms/solana/protocols/cctp/src/circleBridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
SolanaChains,
SolanaPlatform,
SolanaPlatformType,
SolanaTransaction,
SolanaUnsignedTransaction,
} from '@wormhole-foundation/connect-sdk-solana';
import { MessageTransmitter, TokenMessenger } from '.';
Expand Down Expand Up @@ -105,13 +106,10 @@ export class SolanaCircleBridge<N extends Network, C extends SolanaChains>
senderPk,
);

const { blockhash } = await SolanaPlatform.latestBlock(this.connection);
const transaction = new Transaction();
transaction.recentBlockhash = blockhash;
transaction.feePayer = senderPk;
transaction.add(ix);

yield this.createUnsignedTx(transaction, 'CircleBridge.Redeem');
yield this.createUnsignedTx({ transaction }, 'CircleBridge.Redeem');
}

async *transfer(
Expand Down Expand Up @@ -140,13 +138,11 @@ export class SolanaCircleBridge<N extends Network, C extends SolanaChains>
amount,
);

const { blockhash } = await SolanaPlatform.latestBlock(this.connection);
const transaction = new Transaction();
transaction.recentBlockhash = blockhash;
transaction.feePayer = senderPk;
transaction.add(ix);

yield this.createUnsignedTx(transaction, 'CircleBridge.Transfer');
yield this.createUnsignedTx({ transaction }, 'CircleBridge.Transfer');
}

async isTransferCompleted(message: CircleBridge.Message): Promise<boolean> {
Expand Down Expand Up @@ -216,7 +212,7 @@ export class SolanaCircleBridge<N extends Network, C extends SolanaChains>
}

private createUnsignedTx(
txReq: Transaction,
txReq: SolanaTransaction,
description: string,
parallelizable: boolean = false,
): SolanaUnsignedTransaction<N, C> {
Expand Down
29 changes: 13 additions & 16 deletions platforms/solana/protocols/core/src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
SolanaPlatform,
SolanaPlatformType,
SolanaUnsignedTransaction,
SolanaTransaction,
} from '@wormhole-foundation/connect-sdk-solana';
import {
ChainId,
Expand Down Expand Up @@ -127,24 +128,20 @@ export class SolanaWormholeCore<N extends Network, C extends SolanaChains>
fee,
);

const { blockhash } = await SolanaPlatform.latestBlock(this.connection);
const transaction = new Transaction();
transaction.recentBlockhash = blockhash;
transaction.feePayer = payer;
transaction.add(feeTransferIx, postMsgIx);
transaction.partialSign(messageAccount);

yield this.createUnsignedTx(transaction, 'Core.PublishMessage');
yield this.createUnsignedTx(
{ transaction, signers: [messageAccount] },
'Core.PublishMessage',
);
}

async *verifyMessage(sender: AnySolanaAddress, vaa: VAA) {
yield* this.postVaa(sender, vaa);
}

async *postVaa(sender: AnySolanaAddress, vaa: VAA, blockhash?: string) {
if (!blockhash)
({ blockhash } = await SolanaPlatform.latestBlock(this.connection));

async *postVaa(sender: AnySolanaAddress, vaa: VAA) {
const postedVaaAddress = derivePostedVaaKey(
this.coreBridge.programId,
Buffer.from(vaa.hash),
Expand All @@ -171,11 +168,12 @@ export class SolanaWormholeCore<N extends Network, C extends SolanaChains>
const verifySigTx = new Transaction().add(
...verifySignaturesInstructions.slice(i, i + 2),
);
verifySigTx.recentBlockhash = blockhash;
verifySigTx.feePayer = senderAddr;
verifySigTx.partialSign(signatureSet);

yield this.createUnsignedTx(verifySigTx, 'Core.VerifySignature', true);
yield this.createUnsignedTx(
{ transaction: verifySigTx, signers: [signatureSet] },
'Core.VerifySignature',
true,
);
}

// Finally create the VAA posting transaction
Expand All @@ -188,10 +186,9 @@ export class SolanaWormholeCore<N extends Network, C extends SolanaChains>
signatureSet.publicKey,
),
);
postVaaTx.recentBlockhash = blockhash;
postVaaTx.feePayer = senderAddr;

yield this.createUnsignedTx(postVaaTx, 'Core.PostVAA');
yield this.createUnsignedTx({ transaction: postVaaTx }, 'Core.PostVAA');
}

static parseSequenceFromLog(
Expand Down Expand Up @@ -328,7 +325,7 @@ export class SolanaWormholeCore<N extends Network, C extends SolanaChains>
}

private createUnsignedTx(
txReq: Transaction,
txReq: SolanaTransaction,
description: string,
parallelizable: boolean = false,
): SolanaUnsignedTransaction<N, C> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
SolanaChains,
SolanaPlatform,
SolanaPlatformType,
SolanaTransaction,
SolanaUnsignedTransaction,
} from '@wormhole-foundation/connect-sdk-solana';

Expand Down Expand Up @@ -173,18 +174,18 @@ export class SolanaAutomaticTokenBridge<
nonce,
);

const { blockhash } = await SolanaPlatform.latestBlock(this.connection);

transaction.add(transferIx);
transaction.recentBlockhash = blockhash;
transaction.feePayer = senderAddress;

yield this.createUnsignedTx(transaction, 'AutomaticTokenBridge.Transfer');
yield this.createUnsignedTx(
{ transaction },
'AutomaticTokenBridge.Transfer',
);
}

async *redeem(sender: AccountAddress<C>, vaa: AutomaticTokenBridge.VAA) {
const redeemTx = new Transaction();
yield this.createUnsignedTx(redeemTx, 'AutomaticTokenBridge.Redeem');
const transaction = new Transaction();
yield this.createUnsignedTx({ transaction }, 'AutomaticTokenBridge.Redeem');
throw new Error('Method not implemented.');
}

Expand Down Expand Up @@ -327,7 +328,7 @@ export class SolanaAutomaticTokenBridge<
}

private createUnsignedTx(
txReq: Transaction,
txReq: SolanaTransaction,
description: string,
parallelizable: boolean = false,
): SolanaUnsignedTransaction<N, C> {
Expand Down
69 changes: 28 additions & 41 deletions platforms/solana/protocols/tokenBridge/src/tokenBridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
SolanaChains,
SolanaPlatform,
SolanaPlatformType,
SolanaTransaction,
SolanaUnsignedTransaction,
} from '@wormhole-foundation/connect-sdk-solana';
import {
Expand Down Expand Up @@ -211,7 +212,6 @@ export class SolanaTokenBridge<N extends Network, C extends SolanaChains>
): AsyncGenerator<SolanaUnsignedTransaction<N, C>> {
if (!payer) throw new Error('Payer required to create attestation');

const { blockhash } = await SolanaPlatform.latestBlock(this.connection);
const senderAddress = new SolanaAddress(payer).unwrap();
// TODO: createNonce().readUInt32LE(0);
const nonce = 0;
Expand All @@ -235,11 +235,11 @@ export class SolanaTokenBridge<N extends Network, C extends SolanaChains>
);

const transaction = new Transaction().add(transferIx, attestIx);
transaction.recentBlockhash = blockhash;
transaction.feePayer = senderAddress;
transaction.partialSign(messageKey);

yield this.createUnsignedTx(transaction, 'Solana.AttestToken');
yield this.createUnsignedTx(
{ transaction, signers: [messageKey] },
'Solana.AttestToken',
);
}

async *submitAttestation(
Expand All @@ -248,11 +248,10 @@ export class SolanaTokenBridge<N extends Network, C extends SolanaChains>
): AsyncGenerator<SolanaUnsignedTransaction<N, C>> {
if (!payer) throw new Error('Payer required to create attestation');

const { blockhash } = await SolanaPlatform.latestBlock(this.connection);
const senderAddress = new SolanaAddress(payer).unwrap();

// Yield transactions to verify sigs and post the VAA
yield* this.coreBridge.postVaa(senderAddress, vaa, blockhash);
yield* this.coreBridge.postVaa(senderAddress, vaa);

// Now yield the transaction to actually create the token
const transaction = new Transaction().add(
Expand All @@ -264,10 +263,9 @@ export class SolanaTokenBridge<N extends Network, C extends SolanaChains>
vaa,
),
);
transaction.recentBlockhash = blockhash;
transaction.feePayer = senderAddress;

yield this.createUnsignedTx(transaction, 'Solana.CreateWrapped');
yield this.createUnsignedTx({ transaction }, 'Solana.CreateWrapped');
}

private async transferSol(
Expand All @@ -278,7 +276,6 @@ export class SolanaTokenBridge<N extends Network, C extends SolanaChains>
): Promise<SolanaUnsignedTransaction<N, C>> {
// https://github.com/wormhole-foundation/wormhole-connect/blob/development/sdk/src/contexts/solana/context.ts#L245

const { blockhash } = await SolanaPlatform.latestBlock(this.connection);
const senderAddress = new SolanaAddress(sender).unwrap();

// TODO: the payer can actually be different from the sender. We need to allow the user to pass in an optional payer
Expand Down Expand Up @@ -368,7 +365,6 @@ export class SolanaTokenBridge<N extends Network, C extends SolanaChains>
);

const transaction = new Transaction();
transaction.recentBlockhash = blockhash;
transaction.feePayer = payerPublicKey;
transaction.add(
createAncillaryAccountIx,
Expand All @@ -378,9 +374,10 @@ export class SolanaTokenBridge<N extends Network, C extends SolanaChains>
tokenBridgeTransferIx,
closeAccountIx,
);
transaction.partialSign(message, ancillaryKeypair);

return this.createUnsignedTx(transaction, 'TokenBridge.TransferNative');
return this.createUnsignedTx(
{ transaction, signers: [message, ancillaryKeypair] },
'TokenBridge.TransferNative',
);
}

async *transfer(
Expand All @@ -397,7 +394,6 @@ export class SolanaTokenBridge<N extends Network, C extends SolanaChains>
return;
}

const { blockhash } = await SolanaPlatform.latestBlock(this.connection);
const tokenAddress = new SolanaAddress(token).unwrap();
const senderAddress = new SolanaAddress(sender).unwrap();
const senderTokenAddress = await getAssociatedTokenAddress(
Expand Down Expand Up @@ -497,17 +493,16 @@ export class SolanaTokenBridge<N extends Network, C extends SolanaChains>
tokenBridgeTransferIx,
);

transaction.recentBlockhash = blockhash;
transaction.feePayer = senderAddress;
transaction.partialSign(message);

yield this.createUnsignedTx(transaction, 'TokenBridge.TransferTokens');
yield this.createUnsignedTx(
{ transaction, signers: [message] },
'TokenBridge.TransferTokens',
);
}

private async *redeemAndUnwrap(
sender: AnySolanaAddress,
vaa: TokenBridge.TransferVAA,
blockhash: string,
) {
// sender, fee payer
const payerPublicKey = new SolanaAddress(sender).unwrap();
Expand Down Expand Up @@ -566,7 +561,6 @@ export class SolanaTokenBridge<N extends Network, C extends SolanaChains>
);

const transaction = new Transaction();
transaction.recentBlockhash = blockhash;
transaction.feePayer = payerPublicKey;
transaction.add(
completeTransferIx,
Expand All @@ -575,15 +569,13 @@ export class SolanaTokenBridge<N extends Network, C extends SolanaChains>
balanceTransferIx,
closeAccountIx,
);
transaction.partialSign(ancillaryKeypair);
yield this.createUnsignedTx(transaction, 'TokenBridge.RedeemAndUnwrap');
yield this.createUnsignedTx(
{ transaction, signers: [ancillaryKeypair] },
'TokenBridge.RedeemAndUnwrap',
);
}

private async *createAta(
sender: AnySolanaAddress,
token: AnySolanaAddress,
blockhash: string,
) {
private async *createAta(sender: AnySolanaAddress, token: AnySolanaAddress) {
const senderAddress = new SolanaAddress(sender).unwrap();
const tokenAddress = new SolanaAddress(token).unwrap();

Expand All @@ -592,17 +584,16 @@ export class SolanaTokenBridge<N extends Network, C extends SolanaChains>
// If the ata doesn't exist yet, create it
const acctInfo = await this.connection.getAccountInfo(ata);
if (acctInfo === null) {
const ataCreationTx = new Transaction().add(
const transaction = new Transaction().add(
createAssociatedTokenAccountInstruction(
senderAddress,
ata,
senderAddress,
tokenAddress,
),
);
ataCreationTx.feePayer = senderAddress;
ataCreationTx.recentBlockhash = blockhash;
yield this.createUnsignedTx(ataCreationTx, 'Redeem.CreateATA');
transaction.feePayer = senderAddress;
yield this.createUnsignedTx({ transaction }, 'Redeem.CreateATA');
}
}

Expand All @@ -611,19 +602,17 @@ export class SolanaTokenBridge<N extends Network, C extends SolanaChains>
vaa: TokenBridge.TransferVAA,
unwrapNative: boolean = true,
) {
const { blockhash } = await SolanaPlatform.latestBlock(this.connection);

// Find the token address local to this chain
const nativeAddress =
vaa.payload.token.chain === this.chain
? vaa.payload.token.address
: (await this.getWrappedAsset(vaa.payload.token)).toUniversalAddress();

// Create an ATA if necessary
yield* this.createAta(sender, nativeAddress, blockhash);
yield* this.createAta(sender, nativeAddress);

// Post the VAA if necessary
yield* this.coreBridge.postVaa(sender, vaa, blockhash);
yield* this.coreBridge.postVaa(sender, vaa);

// redeem vaa and unwrap to native sol from wrapped sol
if (unwrapNative) {
Expand All @@ -635,7 +624,7 @@ export class SolanaTokenBridge<N extends Network, C extends SolanaChains>
wrappedNative.toUint8Array(),
)
) {
yield* this.redeemAndUnwrap(sender, vaa, blockhash);
yield* this.redeemAndUnwrap(sender, vaa);
return;
}
}
Expand All @@ -656,14 +645,12 @@ export class SolanaTokenBridge<N extends Network, C extends SolanaChains>
vaa,
),
);

transaction.recentBlockhash = blockhash;
transaction.feePayer = senderAddress;
yield this.createUnsignedTx(transaction, 'Solana.RedeemTransfer');
yield this.createUnsignedTx({ transaction }, 'Solana.RedeemTransfer');
}

private createUnsignedTx(
txReq: Transaction,
txReq: SolanaTransaction,
description: string,
parallelizable: boolean = false,
): SolanaUnsignedTransaction<N, C> {
Expand Down
Loading

0 comments on commit 44f2b7c

Please sign in to comment.