Skip to content

Commit 17b87af

Browse files
authored
Examples: Add vaa examples (#584)
1 parent 3c7c756 commit 17b87af

File tree

2 files changed

+220
-8
lines changed

2 files changed

+220
-8
lines changed

README.md

+115-8
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,115 @@ export interface SignAndSendSigner {
208208

209209
See the testing signers ([Evm](https://github.com/wormhole-foundation/connect-sdk/blob/main/platforms/evm/src/signer.ts), [Solana](https://github.com/wormhole-foundation/connect-sdk/blob/main/platforms/solana/src/signer.ts), ...) for an example of how to implement a signer for a specific chain or platform.
210210

211+
### VAAs
212+
213+
Working with VAAs directly may be necessary. The SDK includes an entire layouting package to define the structure of a VAA payload and provides the ability to easily serialize and deserialize the VAAs or VAA payloads.
214+
215+
Using `Uint8Array` as the paylaod type will always work:
216+
<!--EXAMPLE_PARSE_VAA-->
217+
```ts
218+
// Create a fake vaa and serialize it to bytes
219+
// the first argument to `createVAA` describes the payload type
220+
// in this case, just a Uint8Array of bytes
221+
const fakeVaaBytes = serialize(
222+
createVAA("Uint8Array", {
223+
guardianSet: 0,
224+
timestamp: 0,
225+
nonce: 0,
226+
emitterChain: "Solana",
227+
emitterAddress: new UniversalAddress(new Uint8Array(32)),
228+
sequence: 0n,
229+
consistencyLevel: 0,
230+
signatures: [],
231+
payload: encoding.bytes.encode("hi"),
232+
}),
233+
);
234+
// Deserialize the VAA back into a data structure, in this case
235+
// decoding the payload back into bytes.
236+
// Using Uint8Array will always work but you can use a more specific payload layout type
237+
console.log(deserialize("Uint8Array", fakeVaaBytes));
238+
```
239+
See example [here](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/examples/src/parseVaa.ts#L15)
240+
<!--EXAMPLE_PARSE_VAA-->
241+
242+
But more specific types can be used
243+
<!--EXAMPLE_PARSE_TOKEN_TRANSFER_VAA-->
244+
```ts
245+
// Create a token bridge VAA and serialize it
246+
// The payload type argument here is "TokenBridge:Transfer"
247+
// which is defined in the the TokenBridge protocol definition
248+
const tokenBridgeVaaBytes = serialize(
249+
createVAA("TokenBridge:Transfer", {
250+
guardianSet: 0,
251+
timestamp: 0,
252+
nonce: 0,
253+
emitterChain: "Solana",
254+
emitterAddress: new UniversalAddress(new Uint8Array(32)),
255+
sequence: 0n,
256+
consistencyLevel: 0,
257+
signatures: [],
258+
payload: {
259+
fee: 0n,
260+
token: {
261+
amount: 0n,
262+
address: new UniversalAddress(new Uint8Array(32)),
263+
chain: "Solana",
264+
},
265+
to: {
266+
chain: "Ethereum",
267+
address: new UniversalAddress(new Uint8Array(32)),
268+
},
269+
},
270+
}),
271+
);
272+
// Although we know the payload type is "TokenBridge:Transfer",
273+
// we can still deserialize it as a Uint8Array
274+
console.log(deserialize("Uint8Array", tokenBridgeVaaBytes));
275+
// Or use the correct payload type to get a more specific data structure
276+
console.log(deserialize("TokenBridge:Transfer", tokenBridgeVaaBytes));
277+
```
278+
See example [here](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/examples/src/parseVaa.ts#L38)
279+
<!--EXAMPLE_PARSE_TOKEN_TRANSFER_VAA-->
280+
281+
Or define your own
282+
<!--EXAMPLE_PARSE_CUSTOM_VAA-->
283+
```ts
284+
285+
// First define a custom payload layout
286+
const customPayloadLayout = [
287+
// 2 byte integer
288+
{ name: "bar", binary: "uint", size: 2 },
289+
// arbitrary bytes, note this will take the rest of the payload
290+
{ name: "foo", binary: "bytes" },
291+
] as const satisfies Layout;
292+
293+
// Now serialize a VAA with the custom payload layout
294+
const customVaaBytes = serialize(
295+
createVAA("Uint8Array", {
296+
guardianSet: 0,
297+
timestamp: 0,
298+
nonce: 0,
299+
emitterChain: "Solana",
300+
emitterAddress: new UniversalAddress(new Uint8Array(32)),
301+
sequence: 0n,
302+
consistencyLevel: 0,
303+
signatures: [],
304+
// Using `serializeLayout` with the custom layout we created above
305+
payload: serializeLayout(customPayloadLayout, {
306+
bar: 42,
307+
foo: new Uint8Array([1, 2, 3]),
308+
}),
309+
}),
310+
);
311+
// Deserialize the VAA to get the custom payload
312+
const vaa = deserialize("Uint8Array", customVaaBytes);
313+
console.log(encoding.hex.encode(vaa.payload));
314+
console.log(deserializeLayout(customPayloadLayout, vaa.payload));
315+
```
316+
See example [here](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/examples/src/parseVaa.ts#L73)
317+
<!--EXAMPLE_PARSE_CUSTOM_VAA-->
318+
319+
211320
### Protocols
212321

213322
While Wormhole itself is a Generic Message Passing protocol, a number of protocols have been built on top of it to provide specific functionality.
@@ -526,7 +635,7 @@ To provide a more flexible and generic interface, the `Wormhole` class provides
526635
routes.AutomaticPorticoRoute, // Native eth transfers
527636
]);
528637
```
529-
See example [here](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/examples/src/router.ts#L30)
638+
See example [here](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/examples/src/router.ts#L20)
530639
<!--EXAMPLE_RESOLVER_CREATE-->
531640

532641
Once created, the resolver can be used to provide a list of input and possible output tokens.
@@ -553,7 +662,7 @@ Once created, the resolver can be used to provide a list of input and possible o
553662
//grab the first one for the example
554663
const destinationToken = destTokens[0]!;
555664
```
556-
See example [here](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/examples/src/router.ts#L41)
665+
See example [here](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/examples/src/router.ts#L31)
557666
<!--EXAMPLE_RESOLVER_LIST_TOKENS-->
558667

559668
Once the tokens are selected, a `RouteTransferRequest` may be created to provide a list of routes that can fulfil the request
@@ -563,8 +672,6 @@ Once the tokens are selected, a `RouteTransferRequest` may be created to provide
563672
// creating a transfer request fetches token details
564673
// since all routes will need to know about the tokens
565674
const tr = await routes.RouteTransferRequest.create(wh, {
566-
from: sender.address,
567-
to: receiver.address,
568675
source: sendToken,
569676
destination: destinationToken,
570677
});
@@ -573,7 +680,7 @@ Once the tokens are selected, a `RouteTransferRequest` may be created to provide
573680
const foundRoutes = await resolver.findRoutes(tr);
574681
console.log("For the transfer parameters, we found these routes: ", foundRoutes);
575682
```
576-
See example [here](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/examples/src/router.ts#L63)
683+
See example [here](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/examples/src/router.ts#L53)
577684
<!--EXAMPLE_REQUEST_CREATE-->
578685

579686
Choosing the best route is currently left to the developer but strategies might include sorting by output amount or expected time to complete the transfer (no estimate currently provided).
@@ -601,7 +708,7 @@ After choosing the best route, extra parameters like `amount`, `nativeGasDropoff
601708
if (!quote.success) throw quote.error;
602709
console.log("Best route quote: ", quote);
603710
```
604-
See example [here](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/examples/src/router.ts#L83)
711+
See example [here](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/examples/src/router.ts#L71)
605712
<!--EXAMPLE_REQUEST_VALIDATE-->
606713

607714

@@ -611,10 +718,10 @@ Finally, assuming the quote looks good, the route can initiate the request with
611718
```ts
612719
// Now the transfer may be initiated
613720
// A receipt will be returned, guess what you gotta do with that?
614-
const receipt = await bestRoute.initiate(sender.signer, quote);
721+
const receipt = await bestRoute.initiate(sender.signer, quote, receiver.address);
615722
console.log("Initiated transfer with receipt: ", receipt);
616723
```
617-
See example [here](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/examples/src/router.ts#L107)
724+
See example [here](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/examples/src/router.ts#L95)
618725
<!--EXAMPLE_REQUEST_INITIATE-->
619726

620727
Note: See the `router.ts` example in the examples directory for a full working example

examples/src/parseVaa.ts

+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import {
2+
UniversalAddress,
3+
createVAA,
4+
deserialize,
5+
serialize,
6+
encoding,
7+
Layout,
8+
serializeLayout,
9+
deserializeLayout,
10+
serializePayload,
11+
} from "@wormhole-foundation/sdk";
12+
13+
(async function () {
14+
// EXAMPLE_PARSE_VAA
15+
// Create a fake vaa and serialize it to bytes
16+
// the first argument to `createVAA` describes the payload type
17+
// in this case, just a Uint8Array of bytes
18+
const fakeVaaBytes = serialize(
19+
createVAA("Uint8Array", {
20+
guardianSet: 0,
21+
timestamp: 0,
22+
nonce: 0,
23+
emitterChain: "Solana",
24+
emitterAddress: new UniversalAddress(new Uint8Array(32)),
25+
sequence: 0n,
26+
consistencyLevel: 0,
27+
signatures: [],
28+
payload: encoding.bytes.encode("hi"),
29+
}),
30+
);
31+
// Deserialize the VAA back into a data structure, in this case
32+
// decoding the payload back into bytes.
33+
// Using Uint8Array will always work but you can use a more specific payload layout type
34+
console.log(deserialize("Uint8Array", fakeVaaBytes));
35+
// EXAMPLE_PARSE_VAA
36+
37+
// EXAMPLE_PARSE_TOKEN_TRANSFER_VAA
38+
// Create a token bridge VAA and serialize it
39+
// The payload type argument here is "TokenBridge:Transfer"
40+
// which is defined in the the TokenBridge protocol definition
41+
const tokenBridgeVaaBytes = serialize(
42+
createVAA("TokenBridge:Transfer", {
43+
guardianSet: 0,
44+
timestamp: 0,
45+
nonce: 0,
46+
emitterChain: "Solana",
47+
emitterAddress: new UniversalAddress(new Uint8Array(32)),
48+
sequence: 0n,
49+
consistencyLevel: 0,
50+
signatures: [],
51+
payload: {
52+
fee: 0n,
53+
token: {
54+
amount: 0n,
55+
address: new UniversalAddress(new Uint8Array(32)),
56+
chain: "Solana",
57+
},
58+
to: {
59+
chain: "Ethereum",
60+
address: new UniversalAddress(new Uint8Array(32)),
61+
},
62+
},
63+
}),
64+
);
65+
// Although we know the payload type is "TokenBridge:Transfer",
66+
// we can still deserialize it as a Uint8Array
67+
console.log(deserialize("Uint8Array", tokenBridgeVaaBytes));
68+
// Or use the correct payload type to get a more specific data structure
69+
console.log(deserialize("TokenBridge:Transfer", tokenBridgeVaaBytes));
70+
// EXAMPLE_PARSE_TOKEN_TRANSFER_VAA
71+
72+
// EXAMPLE_PARSE_CUSTOM_VAA
73+
74+
// First define a custom payload layout
75+
const customPayloadLayout = [
76+
// 2 byte integer
77+
{ name: "bar", binary: "uint", size: 2 },
78+
// arbitrary bytes, note this will take the rest of the payload
79+
{ name: "foo", binary: "bytes" },
80+
] as const satisfies Layout;
81+
82+
// Now serialize a VAA with the custom payload layout
83+
const customVaaBytes = serialize(
84+
createVAA("Uint8Array", {
85+
guardianSet: 0,
86+
timestamp: 0,
87+
nonce: 0,
88+
emitterChain: "Solana",
89+
emitterAddress: new UniversalAddress(new Uint8Array(32)),
90+
sequence: 0n,
91+
consistencyLevel: 0,
92+
signatures: [],
93+
// Using `serializeLayout` with the custom layout we created above
94+
payload: serializeLayout(customPayloadLayout, {
95+
bar: 42,
96+
foo: new Uint8Array([1, 2, 3]),
97+
}),
98+
}),
99+
);
100+
// Deserialize the VAA to get the custom payload
101+
const vaa = deserialize("Uint8Array", customVaaBytes);
102+
console.log(encoding.hex.encode(vaa.payload));
103+
console.log(deserializeLayout(customPayloadLayout, vaa.payload));
104+
// EXAMPLE_PARSE_CUSTOM_VAA
105+
})();

0 commit comments

Comments
 (0)