Skip to content

Commit 27f4d94

Browse files
authored
Docstrings and more (#298)
1 parent 63a1c1e commit 27f4d94

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+872
-370
lines changed

README.md

+176-132
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
The Connect SDK is a TypeScript SDK for interacting with the chains Wormhole supports and the [protocols](#protocols) built on top of Wormhole.
44

5+
## Warning
6+
7+
:warning: This package is a Work in Progress so the interface may change and there are likely bugs. Please [report](https://github.com/wormhole-foundation/connect-sdk/issues) any issues you find. :warning:
8+
59
## Installation
610

711
Install the primary package
@@ -39,6 +43,8 @@ import { SolanaPlatform } from "@wormhole-foundation/connect-sdk-solana";
3943
import { AlgorandPlatform } from "@wormhole-foundation/connect-sdk-algorand";
4044

4145
// Include the protocols you wish to use
46+
// these imports register the protocol to be used by higher level abstractions
47+
// like WormholeTransfers
4248
import "@wormhole-foundation/connect-sdk-evm-tokenbridge";
4349
import "@wormhole-foundation/connect-sdk-solana-tokenbridge";
4450
import "@wormhole-foundation/connect-sdk-algorand-tokenbridge";
@@ -51,11 +57,180 @@ const wh = new Wormhole(network, [EvmPlatform, SolanaPlatform, AlgorandPlatform]
5157
// look up configuration parameters or even fetch balances
5258
const srcChain = wh.getChain("Ethereum");
5359

60+
// In this SDK, the string literal `'native'` is an alias for the gas token
61+
// native to the chain
5462
const balance = await srcChain.getBalance( "0xdeadbeef...", "native" ) // => BigInt
63+
64+
// returns a TokenBridge client for `srcChain`
5565
await srcChain.getTokenBridge(); // => TokenBridge<'Evm'>
66+
// util to grab an RPC client, cached after the first call
5667
srcChain.getRpc(); // => RpcConnection<'Evm'>
5768
```
5869

70+
## Concepts
71+
72+
Understanding several higher level concepts of the SDK will help in using it effectively.
73+
74+
### Platforms
75+
76+
Every chain is its own special snowflake but many of them share similar functionality. The `Platform` modules provide a consistent interface for interacting with the chains that share a platform.
77+
78+
Each platform can be installed separately so that dependencies can stay as minimal as possible.
79+
80+
### Chain Context
81+
82+
The `Wormhole` class provides a `getChain` method that returns a `ChainContext` object for a given chain. This object provides access to the chain specific methods and utilities. Much of the functionality in the `ChainContext` is provided by the `Platform` methods but the specific chain may have overridden methods.
83+
84+
The ChainContext object is also responsible for holding a cached rpc client and protocol clients.
85+
86+
```ts
87+
// Get the chain context for the source and destination chains
88+
// This is useful to grab direct clients for the protocols
89+
const srcChain = wh.getChain(senderAddress.chain);
90+
const dstChain = wh.getChain(receiverAddress.chain);
91+
92+
const tb = await srcChain.getTokenBridge(); // => TokenBridge<'Evm'>
93+
srcChain.getRpcClient(); // => RpcClient<'Evm'>
94+
```
95+
96+
97+
### Addresses
98+
99+
Within the Wormhole context, addresses are often [normalized](https://docs.wormhole.com/wormhole/blockchain-environments/evm#addresses) to 32 bytes and referred to in this SDK as a `UniversalAddresses`.
100+
101+
Each platform comes with an address type that understands the native address formats, unsurprisingly referred to as NativeAddress. This abstraction allows the SDK to work with addresses in a consistent way regardless of the underlying chain.
102+
103+
```ts
104+
// Its possible to convert a string address to its Native address
105+
const ethAddr: NativeAddress<"Evm"> = toNative("Ethereum", "0xbeef...");
106+
107+
// A common type in the SDK is the `ChainAddress` which provides
108+
// the additional context of the `Chain` this address is relevant for.
109+
const senderAddress: ChainAddress = Wormhole.chainAddress("Ethereum","0xbeef...");
110+
const receiverAddress: ChainAddress = Wormhole.chainAddress("Solana","Sol1111...");
111+
112+
// Convert the ChainAddress back to its canonical string address format
113+
const strAddress = Wormhole.canonicalAddress(senderAddress); // => '0xbeef...'
114+
115+
// Or if the ethAddr above is for an emitter and you need the UniversalAddress
116+
const emitterAddr = ethAddr.toUniversalAddress().toString()
117+
```
118+
119+
### Tokens
120+
121+
Similar to the `ChainAddress` type, the `TokenId` type provides the Chain and Address of a given Token.
122+
123+
```ts
124+
// Returns a TokenId
125+
const sourceToken: TokenId = Wormhole.tokenId("Ethereum","0xbeef...");
126+
127+
// Whereas the ChainAddress is limited to valid addresses, a TokenId may
128+
// have the string literal 'native' to consistently denote the native
129+
// gas token of the chain
130+
const gasToken: TokenId = Wormhole.tokenId("Ethereum","native");
131+
132+
// the same method can be used to convert the TokenId back to its canonical string address format
133+
const strAddress = Wormhole.canonicalAddress(senderAddress); // => '0xbeef...'
134+
```
135+
136+
137+
### Signers
138+
139+
In order to sign transactions, an object that fulfils the `Signer` interface is required. This is a simple interface that can be implemented by wrapping a web wallet or other signing mechanism.
140+
141+
```ts
142+
// A Signer is an interface that must be provided to certain methods
143+
// in the SDK to sign transactions. It can be either a SignOnlySigner
144+
// or a SignAndSendSigner depending on circumstances.
145+
// A Signer can be implemented by wrapping an existing offline wallet
146+
// or a web wallet
147+
export type Signer = SignOnlySigner | SignAndSendSigner;
148+
149+
// A SignOnlySender is for situations where the signer is not
150+
// connected to the network or does not wish to broadcast the
151+
// transactions themselves
152+
export interface SignOnlySigner {
153+
chain(): ChainName;
154+
address(): string;
155+
// Accept an array of unsigned transactions and return
156+
// an array of signed and serialized transactions.
157+
// The transactions may be inspected or altered before
158+
// signing.
159+
// Note: The serialization is chain specific, if in doubt,
160+
// see the example implementations linked below
161+
sign(tx: UnsignedTransaction[]): Promise<SignedTx[]>;
162+
}
163+
164+
// A SignAndSendSigner is for situations where the signer is
165+
// connected to the network and wishes to broadcast the
166+
// transactions themselves
167+
export interface SignAndSendSigner {
168+
chain(): ChainName;
169+
address(): string;
170+
// Accept an array of unsigned transactions and return
171+
// an array of transaction ids in the same order as the
172+
// UnsignedTransactions array.
173+
signAndSend(tx: UnsignedTransaction[]): Promise<TxHash[]>;
174+
}
175+
```
176+
177+
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.
178+
179+
### Protocols
180+
181+
While Wormhole itself is a Generic Message Passing protocol, a number of protocols have been built on top of it to provide specific functionality.
182+
183+
Each Protocol, if available, will have a Platform specific implementation. These implementations provide methods to generate transactions or read state from the contract on-chain.
184+
185+
#### Wormhole Core
186+
187+
The protocol that underlies all Wormhole activity is the Core protocol. This protocol is responsible for emitting the message containing the information necessary to perform bridging including [Emitter address](https://docs.wormhole.com/wormhole/reference/glossary#emitter), the [Sequence number](https://docs.wormhole.com/wormhole/reference/glossary#sequence) for the message and the Payload of the message itself.
188+
189+
```ts
190+
// ...
191+
// register the protocol
192+
import "@wormhole-foundation/connect-sdk-solana-core";
193+
194+
// ...
195+
196+
// get chain context
197+
const chain = wh.getChain("Solana");
198+
// Get the core brige client for Solana
199+
const coreBridge = await chain.getWormholeCore();
200+
// Generate transactions necessary to simply publish a message
201+
const publishTxs = coreBridge.publishMessage(address.address, encoding.bytes.encode("lol"), 0, 0);
202+
203+
// ... posibly later, after fetching the signed VAA, generate the transactions to verify the VAA
204+
const verifyTxs = coreBridge.verifyMessage(address.address, vaa);
205+
```
206+
207+
Within the payload is the information necessary to perform whatever action is required based on the Protocol that uses it.
208+
209+
#### Token Bridge
210+
211+
The most familiar protocol built on Wormhole is the Token Bridge.
212+
213+
Every chain has a `TokenBridge` protocol client that provides a consistent interface for interacting with the Token Bridge. This includes methods to generate the transactions required to transfer tokens, as well as methods to generate and redeem attestations.
214+
215+
Using the `WormholeTransfer` abstractions is the recommended way to interact with these protocols but it is possible to use them directly
216+
217+
```ts
218+
import { signSendWait } from "@wormhole-foundation/connect-sdk";
219+
220+
import "@wormhole-foundation/connect-sdk-evm-tokenbridge";
221+
222+
// ...
223+
224+
const tb = await srcChain.getTokenBridge(); // => TokenBridge<'Evm'>
225+
226+
const token = "0xdeadbeef...";
227+
const txGenerator = tb.createAttestation(token); // => AsyncGenerator<UnsignedTransaction, ...>
228+
const txids = await signSendWait(srcChain, txGenerator, src.signer); // => TxHash[]
229+
```
230+
231+
Supported protocols are defined in the [definitions module](https://github.com/wormhole-foundation/connect-sdk/tree/main/core/definitions/src/protocols).
232+
233+
59234
### Wormhole Transfer
60235

61236
While using the [ChainContext](#chain-context) and [Protocol](#protocols) clients directly is possible, to do things like transfer tokens, the SDK provides some helpful abstractions.
@@ -189,138 +364,7 @@ const xfer = await TokenTransfer.from({
189364
const dstTxIds = await xfer.completeTransfer(dst.signer);
190365
```
191366

192-
## Concepts
193-
194-
Understanding several higher level concepts of the SDK will help in using it effectively.
195-
196-
### Platforms
197-
198-
Every chain is its own special snowflake but many of them share similar functionality. The `Platform` modules provide a consistent interface for interacting with the chains that share a platform.
199-
200-
Each platform can be installed separately so that dependencies can stay as minimal as possible.
201-
202-
### Chain Context
203-
204-
The `Wormhole` class provides a `getChain` method that returns a `ChainContext` object for a given chain. This object provides access to the chain specific methods and utilities. Much of the functionality in the `ChainContext` is provided by the `Platform` methods but the specific chain may have overridden methods.
205-
206-
The ChainContext object is also responsible for holding a cached rpc client and protocol clients.
207-
208-
```ts
209-
// Get the chain context for the source and destination chains
210-
// This is useful to grab direct clients for the protocols
211-
const srcChain = wh.getChain(senderAddress.chain);
212-
const dstChain = wh.getChain(receiverAddress.chain);
213-
214-
srcChain.parseAddress("0xdeadbeef..."); // => NativeAddress<'Evm'>
215-
await srcChain.getTokenBridge(); // => TokenBridge<'Evm'>
216-
srcChain.getRpcClient(); // => RpcClient<'Evm'>
217-
```
218-
219-
### Protocols
220-
221-
While Wormhole itself is a Generic Message Passing protocol, a number of protocols have been built on top of it to provide specific functionality.
222-
223-
#### Token Bridge
224-
225-
The most familiar protocol built on Wormhole is the Token Bridge.
226-
227-
Every chain has a `TokenBridge` protocol client that provides a consistent interface for interacting with the Token Bridge. This includes methods to generate the transactions required to transfer tokens, as well as methods to generate and redeem attestations.
228-
229-
Using the `WormholeTransfer` abstractions is the recommended way to interact with these protocols but it is possible to use them directly
230-
231-
```ts
232-
import { signSendWait } from "@wormhole-foundation/connect-sdk";
233-
234-
import "@wormhole-foundation/connect-sdk-evm-tokenbridge";
235-
236-
// ...
237-
238-
const tb = await srcChain.getTokenBridge(); // => TokenBridge<'Evm'>
239-
240-
const token = "0xdeadbeef...";
241-
const txGenerator = tb.createAttestation(token); // => AsyncGenerator<UnsignedTransaction, ...>
242-
const txids = await signSendWait(srcChain, txGenerator, src.signer); // => TxHash[]
243-
```
244-
245-
Supported protocols are defined in the [definitions module](https://github.com/wormhole-foundation/connect-sdk/tree/main/core/definitions/src/protocols).
246-
247-
### Signers
248-
249-
In order to sign transactions, an object that fulfils the `Signer` interface is required. This is a simple interface that can be implemented by wrapping a web wallet or other signing mechanism.
250-
251-
```ts
252-
// A Signer is an interface that must be provided to certain methods
253-
// in the SDK to sign transactions. It can be either a SignOnlySigner
254-
// or a SignAndSendSigner depending on circumstances.
255-
// A Signer can be implemented by wrapping an existing offline wallet
256-
// or a web wallet
257-
export type Signer = SignOnlySigner | SignAndSendSigner;
258-
259-
// A SignOnlySender is for situations where the signer is not
260-
// connected to the network or does not wish to broadcast the
261-
// transactions themselves
262-
export interface SignOnlySigner {
263-
chain(): ChainName;
264-
address(): string;
265-
// Accept an array of unsigned transactions and return
266-
// an array of signed and serialized transactions.
267-
// The transactions may be inspected or altered before
268-
// signing.
269-
// Note: The serialization is chain specific, if in doubt,
270-
// see the example implementations linked below
271-
sign(tx: UnsignedTransaction[]): Promise<SignedTx[]>;
272-
}
273-
274-
// A SignAndSendSigner is for situations where the signer is
275-
// connected to the network and wishes to broadcast the
276-
// transactions themselves
277-
export interface SignAndSendSigner {
278-
chain(): ChainName;
279-
address(): string;
280-
// Accept an array of unsigned transactions and return
281-
// an array of transaction ids in the same order as the
282-
// UnsignedTransactions array.
283-
signAndSend(tx: UnsignedTransaction[]): Promise<TxHash[]>;
284-
}
285-
```
286-
287-
See the testing signers ([Evm](https://github.com/wormhole-foundation/connect-sdk/blob/main/platforms/evm/src/testing/signer.ts), [Solana](https://github.com/wormhole-foundation/connect-sdk/blob/main/platforms/solana/src/testing/signer.ts), ...) for an example of how to implement a signer for a specific chain or platform.
288-
289-
```ts
290-
// Create a signer for the source and destination chains
291-
const sender: Signer = // ...
292-
const receiver: Signer = // ...
293-
294-
```
295-
296-
### Addresses
297-
298-
Within the Wormhole context, addresses are [normalized](https://docs.wormhole.com/wormhole/blockchain-environments/evm#addresses) to 32 bytes and referred to in this SDK as a `UniversalAddresses`.
299-
300-
Each platform comes with an address type that understands the native address formats, unsurprisingly referred to as NativeAddress. This abstraction allows the SDK to work with addresses in a consistent way regardless of the underlying chain.
301-
302-
```ts
303-
// Convert a string address to its Native address
304-
const ethAddr: NativeAddress<"Evm"> = toNative("Ethereum", "0xbeef...");
305-
const solAddr: NativeAddress<"Solana"> = toNative("Solana", "Sol1111...");
306-
const algoAddr: NativeAddress<"Algorand"> = toNative("Solana", "TRYALGO...");
307-
308-
// Convert a Native address to its string address
309-
ethAddr.toString(); // => '0xbeef...'
310-
311-
// Convert a Native address to a UniversalAddress
312-
ethAddr.toUniversalAddress();
313-
314-
// A common type in the SDK is the `ChainAddress`.
315-
// A helper exists to provide a ChainAddress for a signer, or [ChainName, string address]
316-
const senderAddress: ChainAddress = Wormhole.chainAddress("Ethereum","0xbeef...");
317-
const receiverAddress: ChainAddress = Wormhole.chainAddress("Solana","Sol1111...");
318-
```
319367

320368
## See also
321369

322-
The tsdoc is available [here](https://wormhole-foundation.github.io/connect-sdk/)
323-
324-
## WIP
325-
326-
:warning: This package is a Work in Progress so the interface may change and there are likely bugs. Please [report](https://github.com/wormhole-foundation/connect-sdk/issues) any issues you find. :warning:
370+
The tsdoc is available [here](https://wormhole-foundation.github.io/connect-sdk/)

connect/src/protocols/tokenTransfer.ts

+1-4
Original file line numberDiff line numberDiff line change
@@ -348,10 +348,7 @@ export class TokenTransfer<N extends Network = Network>
348348
key: WormholeMessageId | TxHash,
349349
timeout?: number,
350350
): Promise<TokenTransferVAA> {
351-
const vaa =
352-
typeof key === "string"
353-
? await wh.getVaaByTxHash(key, TokenBridge.getTransferDiscriminator(), timeout)
354-
: await wh.getVaa(key, TokenBridge.getTransferDiscriminator(), timeout);
351+
const vaa = await wh.getVaa(key, TokenBridge.getTransferDiscriminator(), timeout);
355352

356353
if (!vaa) throw new Error(`No VAA available after retries exhausted`);
357354

connect/src/routes/portico/automatic.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ export class AutomaticPorticoRoute<N extends Network>
278278
if (!isSourceInitiated(receipt)) throw new Error("Source must be initiated");
279279

280280
const { txid } = receipt.originTxs[receipt.originTxs.length - 1]!;
281-
const vaa = await this.wh.getVaaByTxHash(txid, "TokenBridge:TransferWithPayload", timeout);
281+
const vaa = await this.wh.getVaa(txid, "TokenBridge:TransferWithPayload", timeout);
282282
if (!vaa) throw new Error("No VAA found for transaction: " + txid);
283283

284284
const parsed = PorticoBridge.deserializePayload(vaa.payload.payload);

connect/src/whscan-api.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@ import { retry } from "./tasks";
1111

1212
export const WHSCAN_RETRY_INTERVAL = 2000;
1313

14-
// TransactionStatus returned by wormholescan
14+
/**
15+
* The status of a transaction
16+
*
17+
* contains information about the transaction and the global transaction if it was relayed
18+
*/
1519
export interface TransactionStatus {
1620
id: string;
1721
timestamp: string;

0 commit comments

Comments
 (0)