Skip to content

Commit 75c7155

Browse files
authored
Solana: Provide ability to resign transactions with ephemeral keys (#195)
1 parent f383a43 commit 75c7155

File tree

12 files changed

+253
-152
lines changed

12 files changed

+253
-152
lines changed

examples/src/helpers/helpers.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
import { getAlgorandSigner } from "@wormhole-foundation/connect-sdk-algorand/src/testing";
1919
import { getCosmwasmSigner } from "@wormhole-foundation/connect-sdk-cosmwasm/src/testing";
2020
import { getEvmSigner } from "@wormhole-foundation/connect-sdk-evm/src/testing";
21-
import { getSolanaSigner } from "@wormhole-foundation/connect-sdk-solana/src/testing";
21+
import { getSolanaSignAndSendSigner } from "@wormhole-foundation/connect-sdk-solana/src/testing";
2222

2323
// Use .env.example as a template for your .env file and populate it with secrets
2424
// for funded accounts on the relevant chain+network combos to run the example
@@ -56,7 +56,7 @@ export async function getStuff<
5656
const platform = chain.platform.utils()._platform;
5757
switch (platform) {
5858
case "Solana":
59-
signer = await getSolanaSigner(await chain.getRpc(), getEnv("SOL_PRIVATE_KEY"));
59+
signer = await getSolanaSignAndSendSigner(await chain.getRpc(), getEnv("SOL_PRIVATE_KEY"));
6060
break;
6161
case "Cosmwasm":
6262
signer = await getCosmwasmSigner(await chain.getRpc(), getEnv("COSMOS_MNEMONIC"));

platforms/solana/__tests__/integration/tokenBridge.test.ts

+9-9
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ describe('TokenBridge Tests', () => {
204204
expect(attestTx.chain).toEqual(chain);
205205

206206
const { transaction } = attestTx;
207-
expect(transaction.instructions).toHaveLength(2);
207+
expect(transaction.transaction.instructions).toHaveLength(2);
208208
});
209209

210210
test('Submit Attestation', async () => {
@@ -229,17 +229,17 @@ describe('TokenBridge Tests', () => {
229229
});
230230
const submitAttestation = tb.submitAttestation(vaa, sender);
231231

232-
const allTxns = [];
232+
const allTxns: SolanaUnsignedTransaction<TNet>[] = [];
233233
for await (const atx of submitAttestation) {
234234
allTxns.push(atx);
235235
}
236236
expect(allTxns).toHaveLength(3);
237237

238238
const [verifySig, postVaa, create] = allTxns;
239239
//
240-
expect(verifySig.transaction.instructions).toHaveLength(2);
241-
expect(postVaa.transaction.instructions).toHaveLength(1);
242-
expect(create.transaction.instructions).toHaveLength(1);
240+
expect(verifySig.transaction.transaction.instructions).toHaveLength(2);
241+
expect(postVaa.transaction.transaction.instructions).toHaveLength(1);
242+
expect(create.transaction.transaction.instructions).toHaveLength(1);
243243
});
244244
});
245245

@@ -260,7 +260,7 @@ describe('TokenBridge Tests', () => {
260260
const xfer = tb.transfer(sender, recipient, token, amount, payload);
261261
expect(xfer).toBeTruthy();
262262

263-
const allTxns = [];
263+
const allTxns: SolanaUnsignedTransaction<TNet>[] = [];
264264
for await (const tx of xfer) {
265265
allTxns.push(tx);
266266
}
@@ -271,7 +271,7 @@ describe('TokenBridge Tests', () => {
271271
expect(xferTx!.chain).toEqual(chain);
272272

273273
const { transaction } = xferTx;
274-
expect(transaction.instructions).toHaveLength(6);
274+
expect(transaction.transaction.instructions).toHaveLength(6);
275275
// ...
276276
});
277277

@@ -285,7 +285,7 @@ describe('TokenBridge Tests', () => {
285285
);
286286
expect(xfer).toBeTruthy();
287287

288-
const allTxns = [];
288+
const allTxns: SolanaUnsignedTransaction<TNet>[] = [];
289289
for await (const tx of xfer) {
290290
allTxns.push(tx);
291291
}
@@ -296,7 +296,7 @@ describe('TokenBridge Tests', () => {
296296
expect(xferTx.chain).toEqual(chain);
297297

298298
const { transaction } = xferTx;
299-
expect(transaction.instructions).toHaveLength(2);
299+
expect(transaction.transaction.instructions).toHaveLength(2);
300300
});
301301
});
302302
});

platforms/solana/protocols/cctp/src/circleBridge.ts

+4-8
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
SolanaChains,
1919
SolanaPlatform,
2020
SolanaPlatformType,
21+
SolanaTransaction,
2122
SolanaUnsignedTransaction,
2223
} from '@wormhole-foundation/connect-sdk-solana';
2324
import { MessageTransmitter, TokenMessenger } from '.';
@@ -105,13 +106,10 @@ export class SolanaCircleBridge<N extends Network, C extends SolanaChains>
105106
senderPk,
106107
);
107108

108-
const { blockhash } = await SolanaPlatform.latestBlock(this.connection);
109109
const transaction = new Transaction();
110-
transaction.recentBlockhash = blockhash;
111110
transaction.feePayer = senderPk;
112111
transaction.add(ix);
113-
114-
yield this.createUnsignedTx(transaction, 'CircleBridge.Redeem');
112+
yield this.createUnsignedTx({ transaction }, 'CircleBridge.Redeem');
115113
}
116114

117115
async *transfer(
@@ -140,13 +138,11 @@ export class SolanaCircleBridge<N extends Network, C extends SolanaChains>
140138
amount,
141139
);
142140

143-
const { blockhash } = await SolanaPlatform.latestBlock(this.connection);
144141
const transaction = new Transaction();
145-
transaction.recentBlockhash = blockhash;
146142
transaction.feePayer = senderPk;
147143
transaction.add(ix);
148144

149-
yield this.createUnsignedTx(transaction, 'CircleBridge.Transfer');
145+
yield this.createUnsignedTx({ transaction }, 'CircleBridge.Transfer');
150146
}
151147

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

218214
private createUnsignedTx(
219-
txReq: Transaction,
215+
txReq: SolanaTransaction,
220216
description: string,
221217
parallelizable: boolean = false,
222218
): SolanaUnsignedTransaction<N, C> {

platforms/solana/protocols/core/src/core.ts

+16-18
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
SolanaPlatform,
1616
SolanaPlatformType,
1717
SolanaUnsignedTransaction,
18+
SolanaTransaction,
1819
} from '@wormhole-foundation/connect-sdk-solana';
1920
import {
2021
ChainId,
@@ -30,14 +31,14 @@ import {
3031
} from '@wormhole-foundation/connect-sdk';
3132
import { Wormhole as WormholeCoreContract } from './types';
3233
import {
33-
BridgeData,
34-
createBridgeFeeTransferInstruction,
3534
createPostMessageInstruction,
3635
createPostVaaInstruction,
3736
createReadOnlyWormholeProgramInterface,
3837
createVerifySignaturesInstructions,
38+
createBridgeFeeTransferInstruction,
3939
derivePostedVaaKey,
4040
getWormholeBridgeData,
41+
BridgeData,
4142
} from './utils';
4243

4344
const SOLANA_SEQ_LOG = 'Program log: Sequence: ';
@@ -82,6 +83,7 @@ export class SolanaWormholeCore<N extends Network, C extends SolanaChains>
8283
throw new Error(
8384
`Network mismatch for chain ${chain}: ${conf.network} != ${network}`,
8485
);
86+
8587
return new SolanaWormholeCore(
8688
network as N,
8789
chain,
@@ -126,24 +128,20 @@ export class SolanaWormholeCore<N extends Network, C extends SolanaChains>
126128
fee,
127129
);
128130

129-
const { blockhash } = await SolanaPlatform.latestBlock(this.connection);
130131
const transaction = new Transaction();
131-
transaction.recentBlockhash = blockhash;
132132
transaction.feePayer = payer;
133133
transaction.add(feeTransferIx, postMsgIx);
134-
transaction.partialSign(messageAccount);
135-
136-
yield this.createUnsignedTx(transaction, 'Core.PublishMessage');
134+
yield this.createUnsignedTx(
135+
{ transaction, signers: [messageAccount] },
136+
'Core.PublishMessage',
137+
);
137138
}
138139

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

143-
async *postVaa(sender: AnySolanaAddress, vaa: VAA, blockhash?: string) {
144-
if (!blockhash)
145-
({ blockhash } = await SolanaPlatform.latestBlock(this.connection));
146-
144+
async *postVaa(sender: AnySolanaAddress, vaa: VAA) {
147145
const postedVaaAddress = derivePostedVaaKey(
148146
this.coreBridge.programId,
149147
Buffer.from(vaa.hash),
@@ -170,11 +168,12 @@ export class SolanaWormholeCore<N extends Network, C extends SolanaChains>
170168
const verifySigTx = new Transaction().add(
171169
...verifySignaturesInstructions.slice(i, i + 2),
172170
);
173-
verifySigTx.recentBlockhash = blockhash;
174171
verifySigTx.feePayer = senderAddr;
175-
verifySigTx.partialSign(signatureSet);
176-
177-
yield this.createUnsignedTx(verifySigTx, 'Core.VerifySignature', true);
172+
yield this.createUnsignedTx(
173+
{ transaction: verifySigTx, signers: [signatureSet] },
174+
'Core.VerifySignature',
175+
true,
176+
);
178177
}
179178

180179
// Finally create the VAA posting transaction
@@ -187,10 +186,9 @@ export class SolanaWormholeCore<N extends Network, C extends SolanaChains>
187186
signatureSet.publicKey,
188187
),
189188
);
190-
postVaaTx.recentBlockhash = blockhash;
191189
postVaaTx.feePayer = senderAddr;
192190

193-
yield this.createUnsignedTx(postVaaTx, 'Core.PostVAA');
191+
yield this.createUnsignedTx({ transaction: postVaaTx }, 'Core.PostVAA');
194192
}
195193

196194
static parseSequenceFromLog(
@@ -327,7 +325,7 @@ export class SolanaWormholeCore<N extends Network, C extends SolanaChains>
327325
}
328326

329327
private createUnsignedTx(
330-
txReq: Transaction,
328+
txReq: SolanaTransaction,
331329
description: string,
332330
parallelizable: boolean = false,
333331
): SolanaUnsignedTransaction<N, C> {

platforms/solana/protocols/tokenBridge/src/automaticTokenBridge.ts

+8-7
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
SolanaChains,
1717
SolanaPlatform,
1818
SolanaPlatformType,
19+
SolanaTransaction,
1920
SolanaUnsignedTransaction,
2021
} from '@wormhole-foundation/connect-sdk-solana';
2122

@@ -173,18 +174,18 @@ export class SolanaAutomaticTokenBridge<
173174
nonce,
174175
);
175176

176-
const { blockhash } = await SolanaPlatform.latestBlock(this.connection);
177-
178177
transaction.add(transferIx);
179-
transaction.recentBlockhash = blockhash;
180178
transaction.feePayer = senderAddress;
181179

182-
yield this.createUnsignedTx(transaction, 'AutomaticTokenBridge.Transfer');
180+
yield this.createUnsignedTx(
181+
{ transaction },
182+
'AutomaticTokenBridge.Transfer',
183+
);
183184
}
184185

185186
async *redeem(sender: AccountAddress<C>, vaa: AutomaticTokenBridge.VAA) {
186-
const redeemTx = new Transaction();
187-
yield this.createUnsignedTx(redeemTx, 'AutomaticTokenBridge.Redeem');
187+
const transaction = new Transaction();
188+
yield this.createUnsignedTx({ transaction }, 'AutomaticTokenBridge.Redeem');
188189
throw new Error('Method not implemented.');
189190
}
190191

@@ -327,7 +328,7 @@ export class SolanaAutomaticTokenBridge<
327328
}
328329

329330
private createUnsignedTx(
330-
txReq: Transaction,
331+
txReq: SolanaTransaction,
331332
description: string,
332333
parallelizable: boolean = false,
333334
): SolanaUnsignedTransaction<N, C> {

0 commit comments

Comments
 (0)