Skip to content

Commit 518f963

Browse files
authored
Merge pull request #9 from wormhole-foundation/themacexpert/buildMulti
Add Wormhole SDK Page
2 parents d9417e1 + d423942 commit 518f963

17 files changed

+1171
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// It's possible to convert a string address to its Native address
2+
const ethAddr: NativeAddress<'Evm'> = toNative('Ethereum', '0xbeef...');
3+
4+
// A common type in the SDK is the `ChainAddress` which provides
5+
// the additional context of the `Chain` this address is relevant for
6+
const senderAddress: ChainAddress = Wormhole.chainAddress(
7+
'Ethereum',
8+
'0xbeef...'
9+
);
10+
const receiverAddress: ChainAddress = Wormhole.chainAddress(
11+
'Solana',
12+
'Sol1111...'
13+
);
14+
15+
// Convert the ChainAddress back to its canonical string address format
16+
const strAddress = Wormhole.canonicalAddress(senderAddress); // => '0xbeef...'
17+
18+
// Or if the ethAddr above is for an emitter and you need the UniversalAddress
19+
const emitterAddr = ethAddr.toUniversalAddress().toString();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import {
2+
Chain,
3+
CircleTransfer,
4+
Network,
5+
Signer,
6+
TransactionId,
7+
TransferState,
8+
Wormhole,
9+
amount,
10+
wormhole,
11+
} from '@wormhole-foundation/sdk';
12+
import evm from '@wormhole-foundation/sdk/evm';
13+
import solana from '@wormhole-foundation/sdk/solana';
14+
import { SignerStuff, getSigner, waitForRelay } from './helpers/index.js';
15+
16+
/*
17+
Notes:
18+
Only a subset of chains are supported by Circle for CCTP, see core/base/src/constants/circle.ts for currently supported chains
19+
20+
AutoRelayer takes a 0.1 USDC fee when transferring to any chain beside Goerli, which is 1 USDC
21+
*/
22+
//
23+
24+
(async function () {
25+
// Init the Wormhole object, passing in the config for which network
26+
// to use (e.g. Mainnet/Testnet) and what Platforms to support
27+
const wh = await wormhole('Testnet', [evm, solana]);
28+
29+
// Grab chain Contexts
30+
const sendChain = wh.getChain('Avalanche');
31+
const rcvChain = wh.getChain('Solana');
32+
33+
// Get signer from local key but anything that implements
34+
// Signer interface (e.g. wrapper around web wallet) should work
35+
const source = await getSigner(sendChain);
36+
const destination = await getSigner(rcvChain);
37+
38+
// 6 decimals for USDC (except for BSC, so check decimals before using this)
39+
const amt = amount.units(amount.parse('0.2', 6));
40+
41+
// Choose whether or not to have the attestation delivered for you
42+
const automatic = false;
43+
44+
// If the transfer is requested to be automatic, you can also request that
45+
// during redemption, the receiver gets some amount of native gas transferred to them
46+
// so that they may pay for subsequent transactions
47+
// The amount specified here is denominated in the token being transferred (USDC here)
48+
const nativeGas = automatic ? amount.units(amount.parse('0.0', 6)) : 0n;
49+
50+
await cctpTransfer(wh, source, destination, {
51+
amount: amt,
52+
automatic,
53+
nativeGas,
54+
});
55+
56+
})();
57+
58+
async function cctpTransfer<N extends Network>(
59+
wh: Wormhole<N>,
60+
src: SignerStuff<N, any>,
61+
dst: SignerStuff<N, any>,
62+
req: {
63+
amount: bigint;
64+
automatic: boolean;
65+
nativeGas?: bigint;
66+
}
67+
) {
68+
69+
const xfer = await wh.circleTransfer(
70+
// Amount as bigint (base units)
71+
req.amount,
72+
// Sender chain/address
73+
src.address,
74+
// Receiver chain/address
75+
dst.address,
76+
// Automatic delivery boolean
77+
req.automatic,
78+
// Payload to be sent with the transfer
79+
undefined,
80+
// If automatic, native gas can be requested to be sent to the receiver
81+
req.nativeGas
82+
);
83+
84+
// Note, if the transfer is requested to be Automatic, a fee for performing the relay
85+
// will be present in the quote. The fee comes out of the amount requested to be sent.
86+
// If the user wants to receive 1.0 on the destination, the amount to send should be 1.0 + fee.
87+
// The same applies for native gas dropoff
88+
const quote = await CircleTransfer.quoteTransfer(
89+
src.chain,
90+
dst.chain,
91+
xfer.transfer
92+
);
93+
console.log('Quote', quote);
94+
95+
console.log('Starting Transfer');
96+
const srcTxids = await xfer.initiateTransfer(src.signer);
97+
console.log(`Started Transfer: `, srcTxids);
98+
99+
if (req.automatic) {
100+
const relayStatus = await waitForRelay(srcTxids[srcTxids.length - 1]!);
101+
console.log(`Finished relay: `, relayStatus);
102+
return;
103+
}
104+
105+
console.log('Waiting for Attestation');
106+
const attestIds = await xfer.fetchAttestation(60_000);
107+
console.log(`Got Attestation: `, attestIds);
108+
109+
console.log('Completing Transfer');
110+
const dstTxids = await xfer.completeTransfer(dst.signer);
111+
console.log(`Completed Transfer: `, dstTxids);
112+
}
113+
114+
export async function completeTransfer(
115+
wh: Wormhole<Network>,
116+
txid: TransactionId,
117+
signer: Signer
118+
): Promise<void> {
119+
120+
const xfer = await CircleTransfer.from(wh, txid);
121+
122+
const attestIds = await xfer.fetchAttestation(60 * 60 * 1000);
123+
console.log('Got attestation: ', attestIds);
124+
125+
const dstTxIds = await xfer.completeTransfer(signer);
126+
console.log('Completed transfer: ', dstTxIds);
127+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
const wh = await wormhole('Testnet', [solana], {
2+
chains: {
3+
Solana: {
4+
contracts: {
5+
coreBridge: '11111111111111111111111111111',
6+
},
7+
rpc: 'https://api.devnet.solana.com',
8+
},
9+
},
10+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { wormhole } from '@wormhole-foundation/sdk';
2+
import solana from '@wormhole-foundation/sdk/solana';
3+
(async function () {
4+
const wh = await wormhole('Testnet', [solana], {
5+
chains: {
6+
Solana: {
7+
contracts: {
8+
coreBridge: '11111111111111111111111111111',
9+
},
10+
rpc: 'https://api.devnet.solana.com',
11+
},
12+
},
13+
});
14+
console.log(wh.config.chains.Solana);
15+
})();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
import {
2+
Chain,
3+
GatewayTransfer,
4+
GatewayTransferDetails,
5+
Network,
6+
TokenId,
7+
Wormhole,
8+
amount,
9+
wormhole,
10+
} from '@wormhole-foundation/sdk';
11+
12+
// Import the platform specific packages
13+
14+
import cosmwasm from '@wormhole-foundation/sdk/cosmwasm';
15+
import evm from '@wormhole-foundation/sdk/evm';
16+
import solana from '@wormhole-foundation/sdk/solana';
17+
import { SignerStuff, getSigner } from './helpers/index.js';
18+
19+
// We're going to transfer into, around, and out of the Cosmos ecosystem
20+
// First on Avalanche, transparently through gateway and over IBC to Cosmoshub
21+
// Then over IBC, transparently through gateway and over IBC to Osmosis
22+
// Finally out of Osmosis, transparently through gateway, out to Avalanche
23+
24+
// eg:
25+
// Avalanche[avax] => {Gateway ->}Osmosis[gateway/wrapped avax]
26+
// Osmosis[gateway/wrapped avax] -> {Gateway ->} Cosmoshub[gateway/wrapped avax]
27+
// Cosmoshub[gateway/wrapped avax] -> {Gateway} => Avalanch[avax]
28+
29+
// Key:
30+
// => : Regular contract call
31+
// -> : IBC Transfer
32+
// {*}: Transparently handled by Gateway
33+
34+
(async function () {
35+
// Init Wormhole object, passing config for which network
36+
// to use (e.g. Mainnet/Testnet) and what Platforms to support
37+
const wh = await wormhole('Mainnet', [evm, solana, cosmwasm]);
38+
// Pick up where you left off by updating the txids as you go
39+
let fakeIt = false;
40+
41+
// Grab chain Contexts for each leg of our journey
42+
const external = wh.getChain('Solana');
43+
const cosmos1 = wh.getChain('Dymension');
44+
const cosmos2 = wh.getChain('Injective');
45+
46+
// Get signer from local key but anything that implements
47+
// Signer interface (e.g. wrapper around web wallet) should work
48+
const leg1 = await getSigner(external);
49+
const leg2 = await getSigner(cosmos1);
50+
const leg3 = await getSigner(cosmos2);
51+
52+
// We'll use the native token on the source chain
53+
const token: TokenId = Wormhole.tokenId(external.chain, 'native');
54+
const amt = amount.units(
55+
amount.parse('0.001', external.config.nativeTokenDecimals)
56+
);
57+
58+
// Transfer native token from source chain, through gateway, to a cosmos chain
59+
let route1 = fakeIt
60+
? await GatewayTransfer.from(
61+
wh,
62+
{
63+
chain: external.chain,
64+
txid: '5y2BnJ1Nwqe4m6KTSrry5Ni88xqVrqo4jdbuNwAPDuXEonQRVLbALf7abViwucKKr8U8cDfJtDmqnuRAAC6i6wtb',
65+
},
66+
600_000
67+
)
68+
: await transferIntoCosmos(wh, token, amt, leg1, leg2);
69+
console.log('Route 1 (External => Cosmos)', route1);
70+
71+
// Lookup the Gateway representation of the wrappd token
72+
const { denom } = route1.ibcTransfers![0]!.data;
73+
const cosmosTokenAddress = Wormhole.parseAddress('Wormchain', denom);
74+
75+
// Transfer Gateway factory tokens over IBC through gateway to another Cosmos chain
76+
let route2 = fakeIt
77+
? await GatewayTransfer.from(
78+
wh,
79+
{
80+
chain: cosmos1.chain,
81+
txid: '3014CABA727C8A1BFCBD282095C771ACBAB3B13CC595B702ABFD3A4502315FBD',
82+
},
83+
600_000
84+
)
85+
: await transferBetweenCosmos(
86+
wh,
87+
{ chain: cosmos1.chain, address: cosmosTokenAddress },
88+
1000n,
89+
leg2,
90+
leg3
91+
);
92+
console.log('Route 2 (Cosmos -> Cosmos): ', route2);
93+
94+
// Transfer Gateway factory token through gateway back to source chain
95+
let route3 = fakeIt
96+
? await GatewayTransfer.from(
97+
wh,
98+
{
99+
chain: cosmos2.chain,
100+
txid: 'BEDD0CE2FEA8FF5DF81FCA5142E72745E154F87D496CDA147FC4D5D46A7C7D81',
101+
},
102+
600_000
103+
)
104+
: await transferOutOfCosmos(
105+
wh,
106+
{ chain: cosmos2.chain, address: cosmosTokenAddress },
107+
1000n,
108+
leg3,
109+
leg1
110+
);
111+
console.log('Route 3 (Cosmos => External): ', route3);
112+
})();
113+
114+
async function transferIntoCosmos(
115+
wh: Wormhole<Network>,
116+
token: TokenId,
117+
amount: bigint,
118+
src: SignerStuff<Network, Chain>,
119+
dst: SignerStuff<Network, Chain>
120+
): Promise<GatewayTransfer<Network>> {
121+
console.log(
122+
`Beginning transfer into Cosmos from ${
123+
src.chain.chain
124+
}:${src.address.address.toString()} to ${
125+
dst.chain.chain
126+
}:${dst.address.address.toString()}`
127+
);
128+
129+
const xfer = await GatewayTransfer.from(wh, {
130+
token: token,
131+
amount: amount,
132+
from: src.address,
133+
to: dst.address,
134+
} as GatewayTransferDetails);
135+
console.log('Created GatewayTransfer: ', xfer.transfer);
136+
137+
const srcTxIds = await xfer.initiateTransfer(src.signer);
138+
console.log('Started transfer on source chain', srcTxIds);
139+
140+
const attests = await xfer.fetchAttestation(600_000);
141+
console.log('Got Attestations', attests);
142+
return xfer;
143+
}
144+
145+
async function transferBetweenCosmos<N extends Network>(
146+
wh: Wormhole<N>,
147+
token: TokenId,
148+
amount: bigint,
149+
src: SignerStuff<N, Chain>,
150+
dst: SignerStuff<N, Chain>
151+
): Promise<GatewayTransfer<N>> {
152+
console.log(
153+
`Beginning transfer within cosmos from ${
154+
src.chain.chain
155+
}:${src.address.address.toString()} to ${
156+
dst.chain.chain
157+
}:${dst.address.address.toString()}`
158+
);
159+
160+
const xfer = await GatewayTransfer.from(wh, {
161+
token: token,
162+
amount: amount,
163+
from: src.address,
164+
to: dst.address,
165+
} as GatewayTransferDetails);
166+
console.log('Created GatewayTransfer: ', xfer.transfer);
167+
168+
const srcTxIds = await xfer.initiateTransfer(src.signer);
169+
console.log('Started transfer on source chain', srcTxIds);
170+
171+
const attests = await xfer.fetchAttestation(60_000);
172+
console.log('Got attests: ', attests);
173+
174+
return xfer;
175+
}
176+
177+
async function transferOutOfCosmos<N extends Network>(
178+
wh: Wormhole<N>,
179+
token: TokenId,
180+
amount: bigint,
181+
src: SignerStuff<N, Chain>,
182+
dst: SignerStuff<N, Chain>
183+
): Promise<GatewayTransfer<N>> {
184+
console.log(
185+
`Beginning transfer out of cosmos from ${
186+
src.chain.chain
187+
}:${src.address.address.toString()} to ${
188+
dst.chain.chain
189+
}:${dst.address.address.toString()}`
190+
);
191+
192+
const xfer = await GatewayTransfer.from(wh, {
193+
token: token,
194+
amount: amount,
195+
from: src.address,
196+
to: dst.address,
197+
} as GatewayTransferDetails);
198+
console.log('Created GatewayTransfer: ', xfer.transfer);
199+
const srcTxIds = await xfer.initiateTransfer(src.signer);
200+
console.log('Started transfer on source chain', srcTxIds);
201+
202+
const attests = await xfer.fetchAttestation(600_000);
203+
console.log('Got attests', attests);
204+
205+
// Since we're leaving cosmos, this is required to complete the transfer
206+
const dstTxIds = await xfer.completeTransfer(dst.signer);
207+
console.log('Completed transfer on destination chain', dstTxIds);
208+
209+
return xfer;
210+
}

0 commit comments

Comments
 (0)