clients/js: attempt sdkV2 migration

This commit is contained in:
Paul Noel 2024-06-12 12:58:02 -05:00
parent 33b2fbe72a
commit 0a55a85291
55 changed files with 8354 additions and 2011 deletions

View File

@ -244,7 +244,7 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: actions/setup-node@v2 - uses: actions/setup-node@v2
with: with:
node-version: "16" node-version: "20"
- run: | - run: |
cd clients/js && make test cd clients/js && make test
make docs make docs

View File

@ -248,16 +248,7 @@ Positionals:
Options: Options:
--help Show help [boolean] --help Show help [boolean]
--version Show version number [boolean] --version Show version number [boolean]
-c, --chain chain name -c, --chain chain name [string]
[choices: "unset", "solana", "ethereum", "terra", "bsc", "polygon",
"avalanche", "oasis", "algorand", "aurora", "fantom", "karura", "acala",
"klaytn", "celo", "near", "moonbeam", "neon", "terra2", "injective",
"osmosis", "sui", "aptos", "arbitrum", "optimism", "gnosis", "pythnet",
"xpla", "btc", "base", "sei", "rootstock", "scroll", "mantle", "blast",
"xlayer", "linea", "berachain", "seievm", "wormchain", "cosmoshub", "evmos",
"kujira", "neutron", "celestia", "stargaze", "seda", "dymension",
"provenance", "sepolia", "arbitrum_sepolia", "base_sepolia",
"optimism_sepolia", "holesky", "polygon_sepolia"]
-n, --network Network -n, --network Network
[required] [choices: "mainnet", "testnet", "devnet"] [required] [choices: "mainnet", "testnet", "devnet"]
-a, --contract-address Contract to submit VAA to (override config) [string] -a, --contract-address Contract to submit VAA to (override config) [string]
@ -307,26 +298,8 @@ Options:
Options: Options:
--help Show help [boolean] --help Show help [boolean]
--version Show version number [boolean] --version Show version number [boolean]
--src-chain source chain --src-chain source chain [string] [required]
[required] [choices: "solana", "ethereum", "terra", "bsc", "polygon", --dst-chain destination chain [string] [required]
"avalanche", "oasis", "algorand", "aurora", "fantom", "karura", "acala",
"klaytn", "celo", "near", "moonbeam", "neon", "terra2", "injective",
"osmosis", "sui", "aptos", "arbitrum", "optimism", "gnosis", "pythnet",
"xpla", "btc", "base", "sei", "rootstock", "scroll", "mantle", "blast",
"xlayer", "linea", "berachain", "seievm", "wormchain", "cosmoshub", "evmos",
"kujira", "neutron", "celestia", "stargaze", "seda", "dymension",
"provenance", "sepolia", "arbitrum_sepolia", "base_sepolia",
"optimism_sepolia", "holesky", "polygon_sepolia"]
--dst-chain destination chain
[required] [choices: "solana", "ethereum", "terra", "bsc", "polygon",
"avalanche", "oasis", "algorand", "aurora", "fantom", "karura", "acala",
"klaytn", "celo", "near", "moonbeam", "neon", "terra2", "injective",
"osmosis", "sui", "aptos", "arbitrum", "optimism", "gnosis", "pythnet",
"xpla", "btc", "base", "sei", "rootstock", "scroll", "mantle", "blast",
"xlayer", "linea", "berachain", "seievm", "wormchain", "cosmoshub", "evmos",
"kujira", "neutron", "celestia", "stargaze", "seda", "dymension",
"provenance", "sepolia", "arbitrum_sepolia", "base_sepolia",
"optimism_sepolia", "holesky", "polygon_sepolia"]
--dst-addr destination address [string] [required] --dst-addr destination address [string] [required]
--token-addr token address [string] [default: native token] --token-addr token address [string] [default: native token]
--amount token amount [string] [required] --amount token amount [string] [required]
@ -353,16 +326,7 @@ Options:
```sh ```sh
Positionals: Positionals:
network Network [choices: "mainnet", "testnet", "devnet"] network Network [choices: "mainnet", "testnet", "devnet"]
chain Source chain chain Source chain [string]
[choices: "unset", "solana", "ethereum", "terra", "bsc", "polygon",
"avalanche", "oasis", "algorand", "aurora", "fantom", "karura", "acala",
"klaytn", "celo", "near", "moonbeam", "neon", "terra2", "injective",
"osmosis", "sui", "aptos", "arbitrum", "optimism", "gnosis", "pythnet",
"xpla", "btc", "base", "sei", "rootstock", "scroll", "mantle", "blast",
"xlayer", "linea", "berachain", "seievm", "wormchain", "cosmoshub", "evmos",
"kujira", "neutron", "celestia", "stargaze", "seda", "dymension",
"provenance", "sepolia", "arbitrum_sepolia", "base_sepolia",
"optimism_sepolia", "holesky", "polygon_sepolia"]
tx Source transaction hash [string] tx Source transaction hash [string]
Options: Options:

File diff suppressed because it is too large Load Diff

View File

@ -42,11 +42,13 @@
"@solana/web3.js": "^1.22.0", "@solana/web3.js": "^1.22.0",
"@terra-money/terra.js": "^3.1.9", "@terra-money/terra.js": "^3.1.9",
"@types/config": "^3.3.0", "@types/config": "^3.3.0",
"@wormhole-foundation/sdk": "^0.7.0-beta.5",
"@xpla/xpla.js": "^0.2.1", "@xpla/xpla.js": "^0.2.1",
"algosdk": "^2.4.0", "algosdk": "^2.4.0",
"aptos": "^1.3.16", "aptos": "^1.3.16",
"axios": "^0.24.0", "axios": "^0.24.0",
"base-64": "^1.0.0", "base-64": "^1.0.0",
"bech32": "^2.0.0",
"binary-parser": "^2.0.2", "binary-parser": "^2.0.2",
"bn.js": "^5.2.0", "bn.js": "^5.2.0",
"bs58": "^4.0.1", "bs58": "^4.0.1",
@ -65,12 +67,13 @@
"@types/bn.js": "^5.1.0", "@types/bn.js": "^5.1.0",
"@types/bs58": "^4.0.1", "@types/bs58": "^4.0.1",
"@types/jest": "^29.5.12", "@types/jest": "^29.5.12",
"@types/node": "^20.12.12",
"@types/node-fetch": "^2.6.3", "@types/node-fetch": "^2.6.3",
"@types/yargs": "^17.0.24", "@types/yargs": "^17.0.24",
"copy-dir": "^1.3.0", "copy-dir": "^1.3.0",
"jest": "^29.7.0", "jest": "^29.7.0",
"ts-jest": "^29.1.2", "ts-jest": "^29.1.2",
"tsx": "^4.12.0", "tsx": "^4.12.0",
"typescript": "^4.6" "typescript": "^5.4.5"
} }
} }

View File

@ -2,24 +2,26 @@ import {
_submitVAAAlgorand, _submitVAAAlgorand,
signSendAndConfirmAlgorand, signSendAndConfirmAlgorand,
} from "@certusone/wormhole-sdk/lib/esm/algorand"; } from "@certusone/wormhole-sdk/lib/esm/algorand";
import {
CONTRACTS,
ChainName,
} from "@certusone/wormhole-sdk/lib/esm/utils/consts";
import { Account, Algodv2, mnemonicToSecretKey } from "algosdk"; import { Account, Algodv2, mnemonicToSecretKey } from "algosdk";
import { NETWORKS } from "./consts"; import { NETWORKS } from "./consts";
import { Network } from "./utils";
import { Payload, impossible } from "./vaa"; import { Payload, impossible } from "./vaa";
import { transferFromAlgorand } from "@certusone/wormhole-sdk/lib/esm/token_bridge/transfer"; import { transferFromAlgorand } from "@certusone/wormhole-sdk/lib/esm/token_bridge/transfer";
import { tryNativeToHexString } from "@certusone/wormhole-sdk/lib/esm/utils"; import { tryNativeToHexString } from "./sdk/array";
import {
Chain,
chainToChainId,
contracts,
Network,
toChainId,
} from "@wormhole-foundation/sdk-base";
export async function execute_algorand( export async function execute_algorand(
payload: Payload, payload: Payload,
vaa: Uint8Array, vaa: Uint8Array,
network: Network network: Network
) { ) {
const chainName = "algorand"; const chain: Chain = "Algorand";
const { key, rpc } = NETWORKS[network][chainName]; const { key, rpc } = NETWORKS[network][chain];
if (!key) { if (!key) {
throw Error(`No ${network} key defined for Algorand`); throw Error(`No ${network} key defined for Algorand`);
} }
@ -28,19 +30,19 @@ export async function execute_algorand(
throw Error(`No ${network} rpc defined for Algorand`); throw Error(`No ${network} rpc defined for Algorand`);
} }
const contracts = CONTRACTS[network][chainName]; const coreContract = contracts.coreBridge(network, chain);
console.log("contracts", contracts); console.log("contracts", contracts);
let target_contract: string; let target_contract: string;
switch (payload.module) { switch (payload.module) {
case "Core": { case "Core": {
if (!contracts.core) { if (!coreContract) {
throw new Error( throw new Error(
`Core bridge address not defined for Algorand ${network}` `Core bridge address not defined for Algorand ${network}`
); );
} }
target_contract = contracts.core; target_contract = coreContract;
switch (payload.type) { switch (payload.type) {
case "GuardianSetUpgrade": case "GuardianSetUpgrade":
console.log("Submitting new guardian set"); console.log("Submitting new guardian set");
@ -57,14 +59,12 @@ export async function execute_algorand(
break; break;
} }
case "NFTBridge": { case "NFTBridge": {
if (!contracts.nft_bridge) { const nftContract = contracts.nftBridge.get(network, chain);
// NOTE: this code can safely be removed once the algorand NFT bridge is if (!nftContract) {
// released, but it's fine for it to stay, as the condition will just be
// skipped once 'contracts.nft_bridge' is defined
throw new Error("NFT bridge not supported yet for Algorand"); throw new Error("NFT bridge not supported yet for Algorand");
} }
target_contract = contracts.nft_bridge; target_contract = nftContract;
switch (payload.type) { switch (payload.type) {
case "ContractUpgrade": case "ContractUpgrade":
console.log("Upgrading contract"); console.log("Upgrading contract");
@ -84,13 +84,14 @@ export async function execute_algorand(
break; break;
} }
case "TokenBridge": { case "TokenBridge": {
if (!contracts.token_bridge) { const tbContract = contracts.tokenBridge(network, chain);
if (!tbContract) {
throw new Error( throw new Error(
`Token bridge address not defined for Algorand ${network}` `Token bridge address not defined for Algorand ${network}`
); );
} }
target_contract = contracts.token_bridge; target_contract = tbContract;
switch (payload.type) { switch (payload.type) {
case "ContractUpgrade": case "ContractUpgrade":
console.log("Upgrading contract"); console.log("Upgrading contract");
@ -121,7 +122,7 @@ export async function execute_algorand(
} }
const target = BigInt(parseInt(target_contract)); const target = BigInt(parseInt(target_contract));
const CORE_ID = BigInt(parseInt(contracts.core)); const CORE_ID = BigInt(parseInt(coreContract));
const algodClient = getClient(network, rpc); const algodClient = getClient(network, rpc);
const algoWallet: Account = mnemonicToSecretKey(key); const algoWallet: Account = mnemonicToSecretKey(key);
@ -140,27 +141,29 @@ export async function execute_algorand(
} }
export async function transferAlgorand( export async function transferAlgorand(
dstChain: ChainName, dstChain: Chain,
dstAddress: string, dstAddress: string,
tokenAddress: string, tokenAddress: string,
amount: string, amount: string,
network: Network, network: Network,
rpc: string rpc: string
) { ) {
const { key } = NETWORKS[network].algorand; const { key } = NETWORKS[network].Algorand;
if (!key) { if (!key) {
throw Error(`No ${network} key defined for Algorand`); throw Error(`No ${network} key defined for Algorand`);
} }
const contracts = CONTRACTS[network].algorand;
const client = getClient(network, rpc); const client = getClient(network, rpc);
const wallet: Account = mnemonicToSecretKey(key); const wallet: Account = mnemonicToSecretKey(key);
const CORE_ID = BigInt(parseInt(contracts.core)); const CORE_ID = BigInt(parseInt(contracts.coreBridge(network, "Algorand")));
const TOKEN_BRIDGE_ID = BigInt(parseInt(contracts.token_bridge)); const TOKEN_BRIDGE_ID = BigInt(
const recipient = tryNativeToHexString(dstAddress, dstChain); parseInt(contracts.tokenBridge(network, "Algorand"))
);
const recipient = tryNativeToHexString(dstAddress, chainToChainId(dstChain));
if (!recipient) { if (!recipient) {
throw new Error("Failed to convert recipient address"); throw new Error("Failed to convert recipient address");
} }
const assetId = tokenAddress === "native" ? BigInt(0) : BigInt(tokenAddress); const assetId = tokenAddress === "native" ? BigInt(0) : BigInt(tokenAddress);
const txs = await transferFromAlgorand( const txs = await transferFromAlgorand(
client, client,
TOKEN_BRIDGE_ID, TOKEN_BRIDGE_ID,
@ -169,7 +172,7 @@ export async function transferAlgorand(
assetId, assetId,
BigInt(amount), BigInt(amount),
recipient, recipient,
dstChain, toChainId(dstChain),
BigInt(0) BigInt(0)
); );
const result = await signSendAndConfirmAlgorand(client, txs, wallet); const result = await signSendAndConfirmAlgorand(client, txs, wallet);
@ -182,7 +185,7 @@ function getClient(network: Network, rpc: string) {
algodServer: rpc, algodServer: rpc,
algodPort: "", algodPort: "",
}; };
if (network === "DEVNET") { if (network === "Devnet") {
ALGORAND_HOST.algodToken = ALGORAND_HOST.algodToken =
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
ALGORAND_HOST.algodPort = "4001"; ALGORAND_HOST.algodPort = "4001";

View File

@ -1,22 +1,21 @@
import {
CONTRACTS,
ChainId,
ChainName,
assertChain,
} from "@certusone/wormhole-sdk/lib/esm/utils/consts";
import { transferFromAptos } from "@certusone/wormhole-sdk/lib/esm/token_bridge/transfer"; import { transferFromAptos } from "@certusone/wormhole-sdk/lib/esm/token_bridge/transfer";
import { AptosAccount, AptosClient, BCS, TxnBuilderTypes, Types } from "aptos"; import { AptosAccount, AptosClient, BCS, TxnBuilderTypes, Types } from "aptos";
import { ethers } from "ethers"; import { ethers } from "ethers";
import { sha3_256 } from "js-sha3"; import { sha3_256 } from "js-sha3";
import { NETWORKS } from "./consts"; import { NETWORKS } from "./consts";
import { Network } from "./utils";
import { Payload, impossible } from "./vaa"; import { Payload, impossible } from "./vaa";
import { CHAINS, ensureHexPrefix } from "@certusone/wormhole-sdk"; import { CHAINS, ensureHexPrefix } from "@certusone/wormhole-sdk";
import { TokenBridgeState } from "@certusone/wormhole-sdk/lib/esm/aptos/types"; import { TokenBridgeState } from "@certusone/wormhole-sdk/lib/esm/aptos/types";
import { generateSignAndSubmitEntryFunction } from "@certusone/wormhole-sdk/lib/esm/utils";
import { import {
generateSignAndSubmitEntryFunction, Chain,
tryNativeToUint8Array, ChainId,
} from "@certusone/wormhole-sdk/lib/esm/utils"; Network,
assertChainId,
contracts,
toChainId,
} from "@wormhole-foundation/sdk-base";
import { tryNativeToUint8Array } from "./sdk/array";
export async function execute_aptos( export async function execute_aptos(
payload: Payload, payload: Payload,
@ -25,7 +24,7 @@ export async function execute_aptos(
contract: string | undefined, contract: string | undefined,
rpc: string | undefined rpc: string | undefined
) { ) {
const chain = "aptos"; const chain: Chain = "Aptos";
// turn VAA bytes into BCS format. That is, add a length prefix // turn VAA bytes into BCS format. That is, add a length prefix
const serializer = new BCS.Serializer(); const serializer = new BCS.Serializer();
@ -34,7 +33,7 @@ export async function execute_aptos(
switch (payload.module) { switch (payload.module) {
case "Core": { case "Core": {
contract = contract ?? CONTRACTS[network][chain]["core"]; contract = contract ?? contracts.coreBridge(network, chain);
if (contract === undefined) { if (contract === undefined) {
throw Error("core bridge contract is undefined"); throw Error("core bridge contract is undefined");
} }
@ -71,7 +70,7 @@ export async function execute_aptos(
break; break;
} }
case "NFTBridge": { case "NFTBridge": {
contract = contract ?? CONTRACTS[network][chain]["nft_bridge"]; contract = contract ?? contracts.nftBridge(network, chain);
if (contract === undefined) { if (contract === undefined) {
throw Error("nft bridge contract is undefined"); throw Error("nft bridge contract is undefined");
} }
@ -120,7 +119,7 @@ export async function execute_aptos(
break; break;
} }
case "TokenBridge": { case "TokenBridge": {
contract = contract ?? CONTRACTS[network][chain]["token_bridge"]; contract = contract ?? contracts.tokenBridge(network, chain);
if (contract === undefined) { if (contract === undefined) {
throw Error("token bridge contract is undefined"); throw Error("token bridge contract is undefined");
} }
@ -180,7 +179,7 @@ export async function execute_aptos(
// offline: // offline:
const tokenAddress = payload.tokenAddress; const tokenAddress = payload.tokenAddress;
const tokenChain = payload.tokenChain; const tokenChain = payload.tokenChain;
assertChain(tokenChain); assertChainId(tokenChain);
let wrappedContract = deriveWrappedAssetAddress( let wrappedContract = deriveWrappedAssetAddress(
hex(contract), hex(contract),
tokenChain, tokenChain,
@ -208,7 +207,7 @@ export async function execute_aptos(
// TODO: only handles wrapped assets for now // TODO: only handles wrapped assets for now
const tokenAddress = payload.tokenAddress; const tokenAddress = payload.tokenAddress;
const tokenChain = payload.tokenChain; const tokenChain = payload.tokenChain;
assertChain(tokenChain); assertChainId(tokenChain);
let wrappedContract = deriveWrappedAssetAddress( let wrappedContract = deriveWrappedAssetAddress(
hex(contract), hex(contract),
tokenChain, tokenChain,
@ -243,22 +242,22 @@ export async function execute_aptos(
} }
export async function transferAptos( export async function transferAptos(
dstChain: ChainName, dstChain: Chain,
dstAddress: string, dstAddress: string,
tokenAddress: string, tokenAddress: string,
amount: string, amount: string,
network: Network, network: Network,
rpc: string rpc: string
) { ) {
const { key } = NETWORKS[network].aptos; const { key } = NETWORKS[network].Aptos;
if (!key) { if (!key) {
throw new Error("No key for aptos"); throw new Error("No key for aptos");
} }
rpc = rpc ?? NETWORKS[network].aptos.rpc; rpc = rpc ?? NETWORKS[network].Aptos.rpc;
if (!rpc) { if (!rpc) {
throw new Error("No rpc for aptos"); throw new Error("No rpc for aptos");
} }
const { token_bridge } = CONTRACTS[network].aptos; const token_bridge = contracts.tokenBridge(network, "Aptos");
if (!token_bridge) { if (!token_bridge) {
throw new Error("token bridge contract is undefined"); throw new Error("token bridge contract is undefined");
} }
@ -268,8 +267,8 @@ export async function transferAptos(
token_bridge, token_bridge,
tokenAddress === "native" ? "0x1::aptos_coin::AptosCoin" : tokenAddress, tokenAddress === "native" ? "0x1::aptos_coin::AptosCoin" : tokenAddress,
amount, amount,
dstChain, toChainId(dstChain),
tryNativeToUint8Array(dstAddress, dstChain) tryNativeToUint8Array(dstAddress, toChainId(dstChain))
); );
const tx = (await generateSignAndSubmitEntryFunction( const tx = (await generateSignAndSubmitEntryFunction(
client, client,
@ -321,14 +320,14 @@ export function deriveResourceAccount(
} }
export async function callEntryFunc( export async function callEntryFunc(
network: "MAINNET" | "TESTNET" | "DEVNET", network: Network,
rpc: string | undefined, rpc: string | undefined,
module: string, module: string,
func: string, func: string,
ty_args: BCS.Seq<TxnBuilderTypes.TypeTag>, ty_args: BCS.Seq<TxnBuilderTypes.TypeTag>,
args: BCS.Seq<BCS.Bytes> args: BCS.Seq<BCS.Bytes>
): Promise<string> { ): Promise<string> {
let key: string | undefined = NETWORKS[network]["aptos"].key; let key: string | undefined = NETWORKS[network]["Aptos"].key;
if (key === undefined) { if (key === undefined) {
throw new Error("No key for aptos"); throw new Error("No key for aptos");
} }
@ -338,7 +337,7 @@ export async function callEntryFunc(
if (typeof rpc != "undefined") { if (typeof rpc != "undefined") {
client = new AptosClient(rpc); client = new AptosClient(rpc);
} else { } else {
client = new AptosClient(NETWORKS[network]["aptos"].rpc); client = new AptosClient(NETWORKS[network]["Aptos"].rpc);
} }
const [{ sequence_number: sequenceNumber }, chainId] = await Promise.all([ const [{ sequence_number: sequenceNumber }, chainId] = await Promise.all([
client.getAccount(accountFrom.address()), client.getAccount(accountFrom.address()),
@ -388,14 +387,13 @@ export async function queryRegistrationsAptos(
network: Network, network: Network,
module: "Core" | "NFTBridge" | "TokenBridge" module: "Core" | "NFTBridge" | "TokenBridge"
): Promise<Object> { ): Promise<Object> {
const n = NETWORKS[network]["aptos"]; const n = NETWORKS[network]["Aptos"];
const client = new AptosClient(n.rpc); const client = new AptosClient(n.rpc);
const contracts = CONTRACTS[network]["aptos"];
let stateObjectId: string | undefined; let stateObjectId: string | undefined;
switch (module) { switch (module) {
case "TokenBridge": case "TokenBridge":
stateObjectId = contracts.token_bridge; stateObjectId = contracts.tokenBridge(network, "Aptos");
if (stateObjectId === undefined) { if (stateObjectId === undefined) {
throw Error(`Unknown token bridge contract on ${network} for Aptos`); throw Error(`Unknown token bridge contract on ${network} for Aptos`);
} }

View File

@ -10,25 +10,38 @@ import {
getOriginalAssetXpla, getOriginalAssetXpla,
} from "@certusone/wormhole-sdk/lib/esm/token_bridge/getOriginalAsset"; } from "@certusone/wormhole-sdk/lib/esm/token_bridge/getOriginalAsset";
import { getOriginalAssetInjective } from "@certusone/wormhole-sdk/lib/esm/token_bridge/injective"; import { getOriginalAssetInjective } from "@certusone/wormhole-sdk/lib/esm/token_bridge/injective";
import {
ChainId,
ChainName,
coalesceChainName,
} from "@certusone/wormhole-sdk/lib/esm/utils/consts";
import { CONTRACTS } from "../../consts";
import { Network } from "../../utils";
import { impossible } from "../../vaa"; import { impossible } from "../../vaa";
import { getOriginalAssetSei } from "../sei/sdk"; import { getOriginalAssetSei } from "../sei/sdk";
import { getProviderForChain } from "./provider"; import { getProviderForChain } from "./provider";
import {
Chain,
ChainId,
Network,
chainToPlatform,
contracts,
toChain,
} from "@wormhole-foundation/sdk-base";
import {
TokenId,
Wormhole,
toChainId,
wormhole,
} from "@wormhole-foundation/sdk";
import evm from "@wormhole-foundation/sdk/evm";
import solana from "@wormhole-foundation/sdk/solana";
import algorand from "@wormhole-foundation/sdk/algorand";
import aptos from "@wormhole-foundation/sdk/aptos";
import cosmwasm from "@wormhole-foundation/sdk/cosmwasm";
import sui from "@wormhole-foundation/sdk/sui";
export const getOriginalAsset = async ( export const getOriginalAsset = async (
chain: ChainId | ChainName, chain: ChainId | Chain,
network: Network, network: Network,
assetAddress: string, assetAddress: string,
rpc?: string rpc?: string
): Promise<WormholeWrappedInfo> => { ): Promise<WormholeWrappedInfo> => {
const chainName = coalesceChainName(chain); const chainName = toChain(chain);
const tokenBridgeAddress = CONTRACTS[network][chainName].token_bridge; const tokenBridgeAddress = contracts.tokenBridge.get(network, chainName);
if (!tokenBridgeAddress) { if (!tokenBridgeAddress) {
throw new Error( throw new Error(
`Token bridge address not defined for ${chainName} ${network}` `Token bridge address not defined for ${chainName} ${network}`
@ -36,69 +49,66 @@ export const getOriginalAsset = async (
} }
switch (chainName) { switch (chainName) {
case "unset": case "Solana": {
throw new Error("Chain not set");
case "solana": {
const provider = getProviderForChain(chainName, network, { rpc }); const provider = getProviderForChain(chainName, network, { rpc });
return getOriginalAssetSolana(provider, tokenBridgeAddress, assetAddress); return getOriginalAssetSolana(provider, tokenBridgeAddress, assetAddress);
} }
case "acala": case "Acala":
case "arbitrum": case "Arbitrum":
case "aurora": case "Aurora":
case "avalanche": case "Avalanche":
case "base": case "Base":
case "bsc": case "Bsc":
case "celo": case "Celo":
case "ethereum": case "Ethereum":
case "fantom": case "Fantom":
case "gnosis": case "Gnosis":
case "karura": case "Karura":
case "klaytn": case "Klaytn":
case "moonbeam": case "Moonbeam":
case "neon": case "Neon":
case "oasis": case "Oasis":
case "optimism": case "Optimism":
case "polygon": case "Polygon":
// case "rootstock": case "Scroll":
case "scroll": case "Mantle":
case "mantle": case "Blast":
case "blast": case "Xlayer":
case "xlayer": case "Linea":
case "linea": case "Berachain":
case "berachain": case "Seievm":
case "seievm": case "Sepolia":
case "sepolia": case "ArbitrumSepolia":
case "arbitrum_sepolia": case "BaseSepolia":
case "base_sepolia": case "OptimismSepolia":
case "optimism_sepolia": case "PolygonSepolia":
case "polygon_sepolia": case "Holesky": {
case "holesky": {
const provider = getProviderForChain(chainName, network, { rpc }); const provider = getProviderForChain(chainName, network, { rpc });
return getOriginalAssetEth( return getOriginalAssetEth(
tokenBridgeAddress, tokenBridgeAddress,
provider, provider,
assetAddress, assetAddress,
chain toChainId(chain)
); );
} }
case "terra": case "Terra":
case "terra2": { case "Terra2": {
const provider = getProviderForChain(chainName, network, { rpc }); const provider = getProviderForChain(chainName, network, { rpc });
return getOriginalAssetTerra(provider, assetAddress); return getOriginalAssetTerra(provider, assetAddress);
} }
case "injective": { case "Injective": {
const provider = getProviderForChain(chainName, network, { rpc }); const provider = getProviderForChain(chainName, network, { rpc });
return getOriginalAssetInjective(assetAddress, provider); return getOriginalAssetInjective(assetAddress, provider);
} }
case "sei": { case "Sei": {
const provider = await getProviderForChain(chainName, network, { rpc }); const provider = await getProviderForChain(chainName, network, { rpc });
return getOriginalAssetSei(assetAddress, provider); return getOriginalAssetSei(assetAddress, provider);
} }
case "xpla": { case "Xpla": {
const provider = getProviderForChain(chainName, network, { rpc }); const provider = getProviderForChain(chainName, network, { rpc });
return getOriginalAssetXpla(provider, assetAddress); return getOriginalAssetXpla(provider, assetAddress);
} }
case "algorand": { case "Algorand": {
const provider = getProviderForChain(chainName, network, { rpc }); const provider = getProviderForChain(chainName, network, { rpc });
return getOriginalAssetAlgorand( return getOriginalAssetAlgorand(
provider, provider,
@ -106,32 +116,32 @@ export const getOriginalAsset = async (
BigInt(assetAddress) BigInt(assetAddress)
); );
} }
case "near": { case "Near": {
const provider = await getProviderForChain(chainName, network, { rpc }); const provider = await getProviderForChain(chainName, network, { rpc });
return getOriginalAssetNear(provider, tokenBridgeAddress, assetAddress); return getOriginalAssetNear(provider, tokenBridgeAddress, assetAddress);
} }
case "aptos": { case "Aptos": {
const provider = getProviderForChain(chainName, network, { rpc }); const provider = getProviderForChain(chainName, network, { rpc });
return getOriginalAssetAptos(provider, tokenBridgeAddress, assetAddress); return getOriginalAssetAptos(provider, tokenBridgeAddress, assetAddress);
} }
case "sui": { case "Sui": {
const provider = getProviderForChain(chainName, network, { rpc }); const provider = getProviderForChain(chainName, network, { rpc });
return getOriginalAssetSui(provider, tokenBridgeAddress, assetAddress); return getOriginalAssetSui(provider, tokenBridgeAddress, assetAddress);
} }
case "btc": case "Btc":
case "osmosis": case "Osmosis":
case "pythnet": case "Pythnet":
case "wormchain": case "Wormchain":
case "cosmoshub": case "Cosmoshub":
case "evmos": case "Evmos":
case "kujira": case "Kujira":
case "neutron": case "Neutron":
case "celestia": case "Celestia":
case "stargaze": case "Stargaze":
case "seda": case "Seda":
case "dymension": case "Dymension":
case "provenance": case "Provenance":
case "rootstock": case "Rootstock":
throw new Error(`${chainName} not supported`); throw new Error(`${chainName} not supported`);
default: default:
impossible(chainName); impossible(chainName);

View File

@ -9,31 +9,32 @@ import {
getForeignAssetXpla, getForeignAssetXpla,
} from "@certusone/wormhole-sdk/lib/esm/token_bridge/getForeignAsset"; } from "@certusone/wormhole-sdk/lib/esm/token_bridge/getForeignAsset";
import { getForeignAssetInjective } from "@certusone/wormhole-sdk/lib/esm/token_bridge/injective"; import { getForeignAssetInjective } from "@certusone/wormhole-sdk/lib/esm/token_bridge/injective";
import { tryNativeToUint8Array } from "@certusone/wormhole-sdk/lib/esm/utils/array";
import {
ChainId,
ChainName,
coalesceChainName,
} from "@certusone/wormhole-sdk/lib/esm/utils/consts";
import { CONTRACTS } from "../../consts";
import { Network } from "../../utils";
import { impossible } from "../../vaa"; import { impossible } from "../../vaa";
import { getForeignAssetSei } from "../sei/sdk"; import { getForeignAssetSei } from "../sei/sdk";
import { getProviderForChain } from "./provider"; import { getProviderForChain } from "./provider";
import {
Chain,
ChainId,
Network,
contracts,
toChain,
toChainId,
} from "@wormhole-foundation/sdk-base";
import { tryNativeToUint8Array } from "../../sdk/array";
export const getWrappedAssetAddress = async ( export const getWrappedAssetAddress = async (
chain: ChainId | ChainName, chain: ChainId | Chain,
network: Network, network: Network,
originChain: ChainId | ChainName, originChain: ChainId | Chain,
originAddress: string, originAddress: string,
rpc?: string rpc?: string
): Promise<string | null> => { ): Promise<string | null> => {
const chainName = coalesceChainName(chain); const chainName = toChain(chain);
const originAddressUint8Array = tryNativeToUint8Array( const originAddressUint8Array = tryNativeToUint8Array(
originAddress, originAddress,
originChain originChain
); );
const tokenBridgeAddress = CONTRACTS[network][chainName].token_bridge; const tokenBridgeAddress = contracts.tokenBridge.get(network, chainName);
if (!tokenBridgeAddress) { if (!tokenBridgeAddress) {
throw new Error( throw new Error(
`Token bridge address not defined for ${chainName} ${network}` `Token bridge address not defined for ${chainName} ${network}`
@ -41,143 +42,141 @@ export const getWrappedAssetAddress = async (
} }
switch (chainName) { switch (chainName) {
case "unset": case "Solana": {
throw new Error("Chain not set");
case "solana": {
const provider = getProviderForChain(chainName, network, { rpc }); const provider = getProviderForChain(chainName, network, { rpc });
return getForeignAssetSolana( return getForeignAssetSolana(
provider, provider,
tokenBridgeAddress, tokenBridgeAddress,
originChain, toChainId(originChain),
originAddressUint8Array originAddressUint8Array
); );
} }
case "acala": case "Acala":
case "arbitrum": case "Arbitrum":
case "aurora": case "Aurora":
case "avalanche": case "Avalanche":
case "base": case "Base":
case "bsc": case "Bsc":
case "celo": case "Celo":
case "ethereum": case "Ethereum":
case "fantom": case "Fantom":
case "gnosis": case "Gnosis":
case "karura": case "Karura":
case "klaytn": case "Klaytn":
case "moonbeam": case "Moonbeam":
case "neon": case "Neon":
case "oasis": case "Oasis":
case "optimism": case "Optimism":
case "polygon": case "Polygon":
// case "rootstock": // case "Rootstock":
case "scroll": case "Scroll":
case "mantle": case "Mantle":
case "blast": case "Blast":
case "xlayer": case "Xlayer":
case "linea": case "Linea":
case "berachain": case "Berachain":
case "seievm": case "Seievm":
case "sepolia": case "Sepolia":
case "arbitrum_sepolia": case "ArbitrumSepolia":
case "base_sepolia": case "BaseSepolia":
case "optimism_sepolia": case "OptimismSepolia":
case "polygon_sepolia": case "PolygonSepolia":
case "holesky": { case "Holesky": {
const provider = getProviderForChain(chainName, network, { rpc }); const provider = getProviderForChain(chainName, network, { rpc });
return getForeignAssetEth( return getForeignAssetEth(
tokenBridgeAddress, tokenBridgeAddress,
provider, provider,
originChain, toChainId(originChain),
originAddressUint8Array originAddressUint8Array
); );
} }
case "terra": case "Terra":
case "terra2": { case "Terra2": {
const provider = getProviderForChain(chainName, network, { rpc }); const provider = getProviderForChain(chainName, network, { rpc });
return getForeignAssetTerra( return getForeignAssetTerra(
tokenBridgeAddress, tokenBridgeAddress,
provider, provider,
originChain, toChainId(originChain),
originAddressUint8Array originAddressUint8Array
); );
} }
case "injective": { case "Injective": {
const provider = getProviderForChain(chainName, network, { rpc }); const provider = getProviderForChain(chainName, network, { rpc });
return getForeignAssetInjective( return getForeignAssetInjective(
tokenBridgeAddress, tokenBridgeAddress,
provider, provider,
originChain, toChainId(originChain),
originAddressUint8Array originAddressUint8Array
); );
} }
case "sei": { case "Sei": {
const provider = await getProviderForChain(chainName, network, { rpc }); const provider = await getProviderForChain(chainName, network, { rpc });
return getForeignAssetSei( return getForeignAssetSei(
tokenBridgeAddress, tokenBridgeAddress,
provider, provider,
originChain, toChainId(originChain),
originAddressUint8Array originAddressUint8Array
); );
} }
case "xpla": { case "Xpla": {
const provider = getProviderForChain(chainName, network, { rpc }); const provider = getProviderForChain(chainName, network, { rpc });
return getForeignAssetXpla( return getForeignAssetXpla(
tokenBridgeAddress, tokenBridgeAddress,
provider, provider,
originChain, toChainId(originChain),
originAddressUint8Array originAddressUint8Array
); );
} }
case "algorand": { case "Algorand": {
const provider = getProviderForChain(chainName, network, { rpc }); const provider = getProviderForChain(chainName, network, { rpc });
return getForeignAssetAlgorand( return getForeignAssetAlgorand(
provider, provider,
BigInt(tokenBridgeAddress), BigInt(tokenBridgeAddress),
originChain, toChainId(originChain),
originAddress originAddress
).then((x) => x?.toString() ?? null); ).then((x) => x?.toString() ?? null);
} }
case "near": { case "Near": {
const provider = await getProviderForChain(chainName, network, { rpc }); const provider = await getProviderForChain(chainName, network, { rpc });
return getForeignAssetNear( return getForeignAssetNear(
provider, provider,
tokenBridgeAddress, tokenBridgeAddress,
originChain, toChainId(originChain),
originAddress originAddress
); );
} }
case "aptos": { case "Aptos": {
const provider = getProviderForChain(chainName, network, { rpc }); const provider = getProviderForChain(chainName, network, { rpc });
return getForeignAssetAptos( return getForeignAssetAptos(
provider, provider,
tokenBridgeAddress, tokenBridgeAddress,
originChain, toChainId(originChain),
originAddress originAddress
); );
} }
case "sui": { case "Sui": {
const provider = getProviderForChain(chainName, network, { rpc }); const provider = getProviderForChain(chainName, network, { rpc });
return getForeignAssetSui( return getForeignAssetSui(
provider, provider,
tokenBridgeAddress, tokenBridgeAddress,
originChain, toChainId(originChain),
originAddressUint8Array originAddressUint8Array
); );
} }
case "btc": case "Btc":
case "osmosis": case "Osmosis":
case "pythnet": case "Pythnet":
case "wormchain": case "Wormchain":
case "cosmoshub": case "Cosmoshub":
case "evmos": case "Evmos":
case "kujira": case "Kujira":
case "neutron": case "Neutron":
case "celestia": case "Celestia":
case "rootstock": case "Rootstock":
case "stargaze": case "Stargaze":
case "seda": case "Seda":
case "dymension": case "Dymension":
case "provenance": case "Provenance":
throw new Error(`${chainName} not supported`); throw new Error(`${chainName} not supported`);
default: default:
impossible(chainName); impossible(chainName);

View File

@ -1,20 +1,3 @@
import {
CHAIN_ID_ALGORAND,
CHAIN_ID_APTOS,
CHAIN_ID_INJECTIVE,
CHAIN_ID_NEAR,
CHAIN_ID_SEI,
CHAIN_ID_SOLANA,
CHAIN_ID_SUI,
CHAIN_ID_TERRA,
CHAIN_ID_TERRA2,
CHAIN_ID_XPLA,
ChainId,
ChainName,
EVMChainId,
EVMChainName,
coalesceChainName,
} from "@certusone/wormhole-sdk/lib/esm/utils/consts";
import { CosmWasmClient } from "@cosmjs/cosmwasm-stargate"; import { CosmWasmClient } from "@cosmjs/cosmwasm-stargate";
import { import {
Network as InjectiveNetwork, Network as InjectiveNetwork,
@ -32,104 +15,107 @@ import { ethers } from "ethers";
import { connect } from "near-api-js"; import { connect } from "near-api-js";
import { Provider as NearProvider } from "near-api-js/lib/providers"; import { Provider as NearProvider } from "near-api-js/lib/providers";
import { NETWORKS } from "../../consts"; import { NETWORKS } from "../../consts";
import { Network } from "../../utils";
import { impossible } from "../../vaa"; import { impossible } from "../../vaa";
import {
Chain,
ChainId,
Network,
PlatformToChains,
chainIds,
toChain,
toChainId,
} from "@wormhole-foundation/sdk-base";
export type ChainProvider<T extends ChainId | ChainName> = T extends export type ChainProvider<T extends Chain> = T extends "Algorand"
| "algorand"
| typeof CHAIN_ID_ALGORAND
? Algodv2 ? Algodv2
: T extends "aptos" | typeof CHAIN_ID_APTOS : T extends "Aptos"
? AptosClient ? AptosClient
: T extends EVMChainName | EVMChainId : T extends PlatformToChains<"Evm">
? ethers.providers.JsonRpcProvider ? ethers.providers.JsonRpcProvider
: T extends "injective" | typeof CHAIN_ID_INJECTIVE : T extends "Injective"
? ChainGrpcWasmApi ? ChainGrpcWasmApi
: T extends "near" | typeof CHAIN_ID_NEAR : T extends "Near"
? Promise<NearProvider> ? Promise<NearProvider>
: T extends : T extends "Terra" | "Terra2"
| "terra"
| "terra2"
| typeof CHAIN_ID_TERRA
| typeof CHAIN_ID_TERRA2
? TerraLCDClient ? TerraLCDClient
: T extends "sei" | typeof CHAIN_ID_SEI : T extends "Sei"
? Promise<CosmWasmClient> ? Promise<CosmWasmClient>
: T extends "solana" | typeof CHAIN_ID_SOLANA : T extends "Solana"
? SolanaConnection ? SolanaConnection
: T extends "sui" | typeof CHAIN_ID_SUI : T extends "Sui"
? JsonRpcProvider ? JsonRpcProvider
: T extends "xpla" | typeof CHAIN_ID_XPLA : T extends "Xpla"
? XplaLCDClient ? XplaLCDClient
: never; : never;
export const getProviderForChain = <T extends ChainId | ChainName>( export const getProviderForChain = <T extends Chain>(
chain: T, chain: T,
network: Network, network: Network,
options?: { rpc?: string; [opt: string]: any } options?: { rpc?: string; [opt: string]: any }
): ChainProvider<T> => { ): ChainProvider<T> => {
const chainName = coalesceChainName(chain); const rpc = options?.rpc ?? NETWORKS[network][chain].rpc;
const rpc = options?.rpc ?? NETWORKS[network][chainName].rpc;
if (!rpc) { if (!rpc) {
throw new Error(`No ${network} rpc defined for ${chainName}`); throw new Error(`No ${network} rpc defined for ${chain}`);
} }
switch (chainName) { switch (chain) {
case "unset": case "Solana":
throw new Error("Chain not set");
case "solana":
return new SolanaConnection(rpc, "confirmed") as ChainProvider<T>; return new SolanaConnection(rpc, "confirmed") as ChainProvider<T>;
case "acala": case "Acala":
case "arbitrum": case "Arbitrum":
case "aurora": case "Aurora":
case "avalanche": case "Avalanche":
case "base": case "Base":
case "bsc": case "Bsc":
case "celo": case "Celo":
case "ethereum": case "Ethereum":
case "fantom": case "Fantom":
case "gnosis": case "Gnosis":
case "karura": case "Karura":
case "klaytn": case "Klaytn":
case "moonbeam": case "Moonbeam":
case "neon": case "Neon":
case "oasis": case "Oasis":
case "optimism": case "Optimism":
case "polygon": case "Polygon":
// case "rootstock": // case "Rootstock":
case "scroll": case "Scroll":
case "mantle": case "Mantle":
case "blast": case "Blast":
case "xlayer": case "Xlayer":
case "linea": case "Linea":
case "berachain": case "Berachain":
case "seievm": case "Seievm":
case "sepolia": case "Sepolia":
case "arbitrum_sepolia": case "ArbitrumSepolia":
case "base_sepolia": case "BaseSepolia":
case "optimism_sepolia": case "OptimismSepolia":
case "polygon_sepolia": case "PolygonSepolia":
case "holesky": case "Holesky":
return new ethers.providers.JsonRpcProvider(rpc) as ChainProvider<T>; return new ethers.providers.JsonRpcProvider(rpc) as ChainProvider<T>;
case "terra": case "Terra":
case "terra2": case "Terra2":
const chain_id =
chain === "Terra"
? NETWORKS[network].Terra.chain_id
: NETWORKS[network].Terra2.chain_id;
return new TerraLCDClient({ return new TerraLCDClient({
URL: rpc, URL: rpc,
chainID: NETWORKS[network][chainName].chain_id, chainID: chain_id,
isClassic: chainName === "terra", isClassic: chain === "Terra",
}) as ChainProvider<T>; }) as ChainProvider<T>;
case "injective": { case "Injective": {
const endpoints = getNetworkEndpoints( const endpoints = getNetworkEndpoints(
network === "MAINNET" network === "Mainnet"
? InjectiveNetwork.MainnetK8s ? InjectiveNetwork.MainnetK8s
: InjectiveNetwork.TestnetK8s : InjectiveNetwork.TestnetK8s
); );
return new ChainGrpcWasmApi(endpoints.grpc) as ChainProvider<T>; return new ChainGrpcWasmApi(endpoints.grpc) as ChainProvider<T>;
} }
case "sei": case "Sei":
return getCosmWasmClient(rpc) as ChainProvider<T>; return getCosmWasmClient(rpc) as ChainProvider<T>;
case "xpla": { case "Xpla": {
const chainId = NETWORKS[network].xpla.chain_id; const chainId = NETWORKS[network].Xpla.chain_id;
if (!chainId) { if (!chainId) {
throw new Error(`No ${network} chain ID defined for XPLA.`); throw new Error(`No ${network} chain ID defined for XPLA.`);
} }
@ -139,7 +125,7 @@ export const getProviderForChain = <T extends ChainId | ChainName>(
chainID: chainId, chainID: chainId,
}) as ChainProvider<T>; }) as ChainProvider<T>;
} }
case "algorand": { case "Algorand": {
const { token, port } = { const { token, port } = {
...{ ...{
token: token:
@ -150,34 +136,34 @@ export const getProviderForChain = <T extends ChainId | ChainName>(
}; };
return new Algodv2(token, rpc, port) as ChainProvider<T>; return new Algodv2(token, rpc, port) as ChainProvider<T>;
} }
case "near": case "Near":
return connect({ return connect({
networkId: NETWORKS[network].near.networkId, networkId: NETWORKS[network].Near.networkId,
nodeUrl: rpc, nodeUrl: rpc,
headers: {}, headers: {},
}).then(({ connection }) => connection.provider) as ChainProvider<T>; }).then(({ connection }) => connection.provider) as ChainProvider<T>;
case "aptos": case "Aptos":
return new AptosClient(rpc) as ChainProvider<T>; return new AptosClient(rpc) as ChainProvider<T>;
case "sui": case "Sui":
return new JsonRpcProvider( return new JsonRpcProvider(
new SuiConnection({ fullnode: rpc }) new SuiConnection({ fullnode: rpc })
) as ChainProvider<T>; ) as ChainProvider<T>;
case "btc": case "Btc":
case "osmosis": case "Osmosis":
case "pythnet": case "Pythnet":
case "wormchain": case "Wormchain":
case "cosmoshub": case "Cosmoshub":
case "evmos": case "Evmos":
case "kujira": case "Kujira":
case "neutron": case "Neutron":
case "celestia": case "Celestia":
case "stargaze": case "Stargaze":
case "seda": case "Seda":
case "dymension": case "Dymension":
case "provenance": case "Provenance":
case "rootstock": case "Rootstock":
throw new Error(`${chainName} not supported`); throw new Error(`${chain} not supported`);
default: default:
impossible(chainName); impossible(chain);
} }
}; };

View File

@ -1,28 +1,22 @@
import { getCosmWasmClient } from "@sei-js/core"; import { getCosmWasmClient } from "@sei-js/core";
import {
ChainName,
CHAINS,
CONTRACTS,
} from "@certusone/wormhole-sdk/lib/esm/utils/consts";
import { NETWORKS } from "../../consts/networks"; import { NETWORKS } from "../../consts/networks";
import { Network } from "../../utils"; import { Chain, Network, chains, contracts } from "@wormhole-foundation/sdk";
export async function queryRegistrationsSei( export async function queryRegistrationsSei(
network: Network, network: Network,
module: "Core" | "NFTBridge" | "TokenBridge" module: "Core" | "NFTBridge" | "TokenBridge"
): Promise<Object> { ): Promise<Object> {
const chain = "sei" as ChainName; const chain: Chain = "Sei";
const n = NETWORKS[network][chain]; const n = NETWORKS[network][chain];
const contracts = CONTRACTS[network][chain];
let target_contract: string | undefined; let target_contract: string | undefined;
switch (module) { switch (module) {
case "TokenBridge": case "TokenBridge":
target_contract = contracts.token_bridge; target_contract = contracts.tokenBridge.get(network, chain);
break; break;
case "NFTBridge": case "NFTBridge":
target_contract = contracts.nft_bridge; target_contract = contracts.nftBridge.get(network, chain);
break; break;
default: default:
throw new Error(`Invalid module: ${module}`); throw new Error(`Invalid module: ${module}`);
@ -41,14 +35,14 @@ export async function queryRegistrationsSei(
// Query the bridge registration for all the chains in parallel. // Query the bridge registration for all the chains in parallel.
const registrations = await Promise.all( const registrations = await Promise.all(
Object.entries(CHAINS) chains
.filter(([c_name, _]) => c_name !== chain && c_name !== "unset") .filter((c_name) => c_name !== chain)
.map(async ([c_name, c_id]) => [ .map(async (c_name) => [
c_name, c_name,
await (async () => { await (async () => {
let query_msg = { let query_msg = {
chain_registration: { chain_registration: {
chain: c_id, chain: c_name,
}, },
}; };

View File

@ -5,13 +5,13 @@ import {
} from "@certusone/wormhole-sdk/lib/esm/cosmwasm/address"; } from "@certusone/wormhole-sdk/lib/esm/cosmwasm/address";
import { WormholeWrappedInfo } from "@certusone/wormhole-sdk/lib/esm/token_bridge/getOriginalAsset"; import { WormholeWrappedInfo } from "@certusone/wormhole-sdk/lib/esm/token_bridge/getOriginalAsset";
import { hexToUint8Array } from "@certusone/wormhole-sdk/lib/esm/utils/array"; import { hexToUint8Array } from "@certusone/wormhole-sdk/lib/esm/utils/array";
import {
CHAIN_ID_SEI,
ChainId,
ChainName,
coalesceChainId,
} from "@certusone/wormhole-sdk/lib/esm/utils/consts";
import { CosmWasmClient } from "@cosmjs/cosmwasm-stargate"; import { CosmWasmClient } from "@cosmjs/cosmwasm-stargate";
import {
Chain,
ChainId,
chainToChainId,
toChainId,
} from "@wormhole-foundation/sdk";
import { fromUint8Array } from "js-base64"; import { fromUint8Array } from "js-base64";
/** /**
@ -25,7 +25,7 @@ import { fromUint8Array } from "js-base64";
export async function getForeignAssetSei( export async function getForeignAssetSei(
tokenBridgeAddress: string, tokenBridgeAddress: string,
cosmwasmClient: CosmWasmClient, cosmwasmClient: CosmWasmClient,
originChain: ChainId | ChainName, originChain: ChainId | Chain,
originAsset: Uint8Array originAsset: Uint8Array
): Promise<string | null> { ): Promise<string | null> {
try { try {
@ -33,7 +33,7 @@ export async function getForeignAssetSei(
tokenBridgeAddress, tokenBridgeAddress,
{ {
wrapped_registry: { wrapped_registry: {
chain: coalesceChainId(originChain), chain: toChainId(originChain),
address: fromUint8Array(originAsset), address: fromUint8Array(originAsset),
}, },
} }
@ -74,7 +74,7 @@ export async function getOriginalAssetSei(
wrappedAddress: string, wrappedAddress: string,
client: CosmWasmClient client: CosmWasmClient
): Promise<WormholeWrappedInfo> { ): Promise<WormholeWrappedInfo> {
const chainId = CHAIN_ID_SEI; const chainId = chainToChainId("Sei");
if (isNativeCosmWasmDenom(chainId, wrappedAddress)) { if (isNativeCosmWasmDenom(chainId, wrappedAddress)) {
return { return {
isWrapped: false, isWrapped: false,

View File

@ -5,10 +5,9 @@ import { toUtf8 } from "@cosmjs/encoding";
import { MsgExecuteContract } from "cosmjs-types/cosmwasm/wasm/v1/tx"; import { MsgExecuteContract } from "cosmjs-types/cosmwasm/wasm/v1/tx";
import { getSigningCosmWasmClient } from "@sei-js/core"; import { getSigningCosmWasmClient } from "@sei-js/core";
import { CONTRACTS } from "@certusone/wormhole-sdk/lib/esm/utils/consts";
import { NETWORKS } from "../../consts"; import { NETWORKS } from "../../consts";
import { Network } from "../../utils";
import { impossible, Payload } from "../../vaa"; import { impossible, Payload } from "../../vaa";
import { contracts, Network } from "@wormhole-foundation/sdk";
export const submit = async ( export const submit = async (
payload: Payload, payload: Payload,
@ -16,8 +15,7 @@ export const submit = async (
network: Network, network: Network,
rpc?: string rpc?: string
) => { ) => {
const contracts = CONTRACTS[network].sei; const networkInfo = NETWORKS[network].Sei;
const networkInfo = NETWORKS[network].sei;
rpc = rpc || networkInfo.rpc; rpc = rpc || networkInfo.rpc;
const key = networkInfo.key; const key = networkInfo.key;
if (!key) { if (!key) {
@ -32,12 +30,12 @@ export const submit = async (
let execute_msg: object; let execute_msg: object;
switch (payload.module) { switch (payload.module) {
case "Core": { case "Core": {
if (!contracts.core) { const core = contracts.coreBridge.get(network, "Sei");
if (!core) {
throw new Error(`Core bridge address not defined for Sei ${network}`); throw new Error(`Core bridge address not defined for Sei ${network}`);
} }
target_contract = contracts.core; target_contract = core;
// sigh...
execute_msg = { execute_msg = {
submit_v_a_a: { submit_v_a_a: {
vaa: vaa.toString("base64"), vaa: vaa.toString("base64"),
@ -59,14 +57,12 @@ export const submit = async (
break; break;
} }
case "NFTBridge": { case "NFTBridge": {
if (!contracts.nft_bridge) { const nft = contracts.nftBridge.get(network, "Sei");
// NOTE: this code can safely be removed once the sei NFT bridge is if (!nft) {
// released, but it's fine for it to stay, as the condition will just be
// skipped once 'contracts.nft_bridge' is defined
throw new Error("NFT bridge not supported yet for Sei"); throw new Error("NFT bridge not supported yet for Sei");
} }
target_contract = contracts.nft_bridge; target_contract = nft;
execute_msg = { execute_msg = {
submit_vaa: { submit_vaa: {
data: vaa.toString("base64"), data: vaa.toString("base64"),
@ -91,11 +87,12 @@ export const submit = async (
break; break;
} }
case "TokenBridge": { case "TokenBridge": {
if (!contracts.token_bridge) { const tb = contracts.tokenBridge.get(network, "Sei");
if (!tb) {
throw new Error(`Token bridge address not defined for Sei ${network}`); throw new Error(`Token bridge address not defined for Sei ${network}`);
} }
target_contract = contracts.token_bridge; target_contract = tb;
execute_msg = { execute_msg = {
submit_vaa: { submit_vaa: {
data: vaa.toString("base64"), data: vaa.toString("base64"),

View File

@ -1,6 +1,5 @@
import { JsonRpcProvider } from "@mysten/sui.js"; import { JsonRpcProvider } from "@mysten/sui.js";
import fs from "fs"; import fs from "fs";
import { Network } from "../../utils";
import { MoveToml } from "./MoveToml"; import { MoveToml } from "./MoveToml";
import { import {
buildPackage, buildPackage,
@ -12,6 +11,7 @@ import {
} from "./publish"; } from "./publish";
import { SuiBuildOutput } from "./types"; import { SuiBuildOutput } from "./types";
import { getPackageId } from "./utils"; import { getPackageId } from "./utils";
import { Network } from "@wormhole-foundation/sdk";
export const buildCoin = async ( export const buildCoin = async (
provider: JsonRpcProvider, provider: JsonRpcProvider,
@ -93,8 +93,8 @@ const setupCoin = (
for (const dependencyPath of paths) { for (const dependencyPath of paths) {
// todo(aki): the 4th param is a hack that makes this work, but doesn't // todo(aki): the 4th param is a hack that makes this work, but doesn't
// necessarily make sense. We should probably revisit this later. // necessarily make sense. We should probably revisit this later.
setupMainToml(dependencyPath, network, false, network !== "DEVNET"); setupMainToml(dependencyPath, network, false, network !== "Devnet");
if (network === "DEVNET") { if (network === "Devnet") {
const dependencyToml = new MoveToml(getDefaultTomlPath(dependencyPath)); const dependencyToml = new MoveToml(getDefaultTomlPath(dependencyPath));
switch (getPackageNameFromPath(dependencyPath)) { switch (getPackageNameFromPath(dependencyPath)) {
case "wormhole": case "wormhole":

View File

@ -8,10 +8,10 @@ import {
import { execSync } from "child_process"; import { execSync } from "child_process";
import fs from "fs"; import fs from "fs";
import { resolve } from "path"; import { resolve } from "path";
import { Network } from "../../utils";
import { MoveToml } from "./MoveToml"; import { MoveToml } from "./MoveToml";
import { SuiBuildOutput } from "./types"; import { SuiBuildOutput } from "./types";
import { executeTransactionBlock } from "./utils"; import { executeTransactionBlock } from "./utils";
import { Network } from "@wormhole-foundation/sdk";
export const buildPackage = (packagePath: string): SuiBuildOutput => { export const buildPackage = (packagePath: string): SuiBuildOutput => {
if (!fs.existsSync(packagePath)) { if (!fs.existsSync(packagePath)) {
@ -76,7 +76,7 @@ export const publishPackage = async (
// Publish contracts // Publish contracts
const tx = new TransactionBlock(); const tx = new TransactionBlock();
if (network === "DEVNET") { if (network === "Devnet") {
// Avoid Error checking transaction input objects: GasBudgetTooHigh { gas_budget: 50000000000, max_budget: 10000000000 } // Avoid Error checking transaction input objects: GasBudgetTooHigh { gas_budget: 50000000000, max_budget: 10000000000 }
tx.setGasBudget(10000000000); tx.setGasBudget(10000000000);
} }
@ -186,7 +186,7 @@ export const setupMainToml = (
// don't have to manually reset them repeatedly during local development. // don't have to manually reset them repeatedly during local development.
// This is not recursive because we assume that packages are deployed bottom // This is not recursive because we assume that packages are deployed bottom
// up. // up.
if (!isDependency && network === "DEVNET") { if (!isDependency && network === "Devnet") {
resetNetworkToml(packagePath, network); resetNetworkToml(packagePath, network);
} }

View File

@ -1,25 +1,24 @@
import { getObjectFields } from "@certusone/wormhole-sdk/lib/esm/sui"; import { getObjectFields } from "@certusone/wormhole-sdk/lib/esm/sui";
import {
CHAIN_ID_TO_NAME,
CONTRACTS,
} from "@certusone/wormhole-sdk/lib/esm/utils/consts";
import { NETWORKS } from "../../consts/networks"; import { NETWORKS } from "../../consts/networks";
import { Network } from "../../utils";
import { getProvider } from "./utils"; import { getProvider } from "./utils";
import { ChainId } from "@certusone/wormhole-sdk"; import {
ChainId,
Network,
chainIdToChain,
contracts,
} from "@wormhole-foundation/sdk";
export async function queryRegistrationsSui( export async function queryRegistrationsSui(
network: Network, network: Network,
module: "Core" | "NFTBridge" | "TokenBridge" module: "Core" | "NFTBridge" | "TokenBridge"
): Promise<Object> { ): Promise<Object> {
const n = NETWORKS[network]["sui"]; const n = NETWORKS[network]["Sui"];
const provider = getProvider(network, n.rpc); const provider = getProvider(network, n.rpc);
const contracts = CONTRACTS[network]["sui"];
let state_object_id: string; let state_object_id: string;
switch (module) { switch (module) {
case "TokenBridge": case "TokenBridge":
state_object_id = contracts.token_bridge; state_object_id = contracts.tokenBridge(network, "Sui");
if (state_object_id === undefined) { if (state_object_id === undefined) {
throw Error(`Unknown token bridge contract on ${network} for Sui`); throw Error(`Unknown token bridge contract on ${network} for Sui`);
} }
@ -49,7 +48,7 @@ export async function queryRegistrationsSui(
const emitterAddress: Uint8Array = const emitterAddress: Uint8Array =
emitter.data?.content?.fields.value.fields.value.fields.data; emitter.data?.content?.fields.value.fields.value.fields.data;
const emitterAddrStr = Buffer.from(emitterAddress).toString("hex"); const emitterAddrStr = Buffer.from(emitterAddress).toString("hex");
results[CHAIN_ID_TO_NAME[chainId]] = emitterAddrStr; results[chainIdToChain(chainId)] = emitterAddrStr;
} }
} }

View File

@ -6,16 +6,7 @@ import {
createWrappedOnSui, createWrappedOnSui,
createWrappedOnSuiPrepare, createWrappedOnSuiPrepare,
} from "@certusone/wormhole-sdk/lib/esm/token_bridge/createWrapped"; } from "@certusone/wormhole-sdk/lib/esm/token_bridge/createWrapped";
import { getForeignAssetSui } from "@certusone/wormhole-sdk/lib/esm/token_bridge/getForeignAsset";
import {
CHAIN_ID_SUI,
CHAIN_ID_TO_NAME,
CONTRACTS,
assertChain,
} from "@certusone/wormhole-sdk/lib/esm/utils/consts";
import { parseAttestMetaVaa } from "@certusone/wormhole-sdk/lib/esm/vaa/tokenBridge";
import { SUI_CLOCK_OBJECT_ID, TransactionBlock } from "@mysten/sui.js"; import { SUI_CLOCK_OBJECT_ID, TransactionBlock } from "@mysten/sui.js";
import { Network } from "../../utils";
import { Payload, impossible } from "../../vaa"; import { Payload, impossible } from "../../vaa";
import { import {
assertSuccess, assertSuccess,
@ -28,6 +19,15 @@ import {
registerChain, registerChain,
setMaxGasBudgetDevnet, setMaxGasBudgetDevnet,
} from "./utils"; } from "./utils";
import {
Chain,
Network,
VAA,
assertChain,
contracts,
deserialize,
} from "@wormhole-foundation/sdk";
import { getForeignAssetSui } from "../../sdk/sui";
export const submit = async ( export const submit = async (
payload: Payload, payload: Payload,
@ -39,13 +39,13 @@ export const submit = async (
const consoleWarnTemp = console.warn; const consoleWarnTemp = console.warn;
console.warn = () => {}; console.warn = () => {};
const chain = CHAIN_ID_TO_NAME[CHAIN_ID_SUI]; const chain: Chain = "Sui";
const provider = getProvider(network, rpc); const provider = getProvider(network, rpc);
const signer = getSigner(provider, network, privateKey); const signer = getSigner(provider, network, privateKey);
switch (payload.module) { switch (payload.module) {
case "Core": { case "Core": {
const coreObjectId = CONTRACTS[network][chain].core; const coreObjectId = contracts.coreBridge(network, chain);
if (!coreObjectId) { if (!coreObjectId) {
throw Error("Core bridge object ID is undefined"); throw Error("Core bridge object ID is undefined");
} }
@ -103,12 +103,12 @@ export const submit = async (
throw new Error("NFT bridge not supported on Sui"); throw new Error("NFT bridge not supported on Sui");
} }
case "TokenBridge": { case "TokenBridge": {
const coreBridgeStateObjectId = CONTRACTS[network][chain].core; const coreBridgeStateObjectId = contracts.coreBridge(network, chain);
if (!coreBridgeStateObjectId) { if (!coreBridgeStateObjectId) {
throw Error("Core bridge object ID is undefined"); throw Error("Core bridge object ID is undefined");
} }
const tokenBridgeStateObjectId = CONTRACTS[network][chain].token_bridge; const tokenBridgeStateObjectId = contracts.tokenBridge(network, chain);
if (!tokenBridgeStateObjectId) { if (!tokenBridgeStateObjectId) {
throw Error("Token bridge object ID is undefined"); throw Error("Token bridge object ID is undefined");
} }
@ -116,13 +116,19 @@ export const submit = async (
switch (payload.type) { switch (payload.type) {
case "AttestMeta": { case "AttestMeta": {
// Test attest VAA: 01000000000100d87023087588d8a482d6082c57f3c93649c9a61a98848fc3a0b271f4041394ff7b28abefc8e5e19b83f45243d073d677e122e41425c2dbae3eb5ae1c7c0ac0ee01000000c056a8000000020000000000000000000000000290fb167208af455bb137780163b7b7a9a10c16000000000000000001020000000000000000000000002d8be6bf0baa74e0a907016679cae9190e80dd0a000212544b4e0000000000000000000000000000000000000000000000000000000000457468657265756d205465737420546f6b656e00000000000000000000000000 // Test attest VAA: 01000000000100d87023087588d8a482d6082c57f3c93649c9a61a98848fc3a0b271f4041394ff7b28abefc8e5e19b83f45243d073d677e122e41425c2dbae3eb5ae1c7c0ac0ee01000000c056a8000000020000000000000000000000000290fb167208af455bb137780163b7b7a9a10c16000000000000000001020000000000000000000000002d8be6bf0baa74e0a907016679cae9190e80dd0a000212544b4e0000000000000000000000000000000000000000000000000000000000457468657265756d205465737420546f6b656e00000000000000000000000000
const { tokenChain, tokenAddress } = parseAttestMetaVaa(vaa); const parsedAttest: VAA<"TokenBridge:AttestMeta"> = deserialize(
"TokenBridge:AttestMeta",
vaa
);
const tokenChain = parsedAttest.payload.token.chain;
assertChain(tokenChain); assertChain(tokenChain);
const tokenAddress = parsedAttest.payload.token.address;
const decimals = parsedAttest.payload.decimals;
const coinType = await getForeignAssetSui( const coinType = await getForeignAssetSui(
provider, provider,
tokenBridgeStateObjectId, tokenBridgeStateObjectId,
tokenChain, tokenChain,
tokenAddress tokenAddress.toUint8Array()
); );
if (coinType) { if (coinType) {
// Coin already exists, so we update it // Coin already exists, so we update it
@ -135,7 +141,7 @@ export const submit = async (
provider, provider,
coreBridgeStateObjectId, coreBridgeStateObjectId,
tokenBridgeStateObjectId, tokenBridgeStateObjectId,
parseAttestMetaVaa(vaa).decimals, decimals,
await signer.getAddress() await signer.getAddress()
); );
setMaxGasBudgetDevnet(network, prepareTx); setMaxGasBudgetDevnet(network, prepareTx);
@ -153,7 +159,7 @@ export const submit = async (
console.log(` Published to ${coinPackageId}`); console.log(` Published to ${coinPackageId}`);
console.log(` Type ${getWrappedCoinType(coinPackageId)}`); console.log(` Type ${getWrappedCoinType(coinPackageId)}`);
if (!rpc && network !== "DEVNET") { if (!rpc && network !== "Devnet") {
// Wait for wrapped asset creation to be propagated to other // Wait for wrapped asset creation to be propagated to other
// nodes in case this complete registration call is load balanced // nodes in case this complete registration call is load balanced
// to another node. // to another node.

View File

@ -6,24 +6,26 @@ import {
setMaxGasBudgetDevnet, setMaxGasBudgetDevnet,
} from "./utils"; } from "./utils";
import { import {
CONTRACTS, Chain,
ChainName,
Network, Network,
tryNativeToUint8Array, chainToChainId,
} from "@certusone/wormhole-sdk/lib/esm/utils"; contracts,
} from "@wormhole-foundation/sdk-base";
import { tryNativeToUint8Array } from "../../sdk/array";
export async function transferSui( export async function transferSui(
dstChain: ChainName, dstChain: Chain,
dstAddress: string, dstAddress: string,
tokenAddress: string, tokenAddress: string,
amount: string, amount: string,
network: Network, network: Network,
rpc: string rpc: string
) { ) {
const { core, token_bridge } = CONTRACTS[network]["sui"]; const core = contracts.coreBridge(network, "Sui");
if (!core) { if (!core) {
throw Error("Core bridge object ID is undefined"); throw Error("Core bridge object ID is undefined");
} }
const token_bridge = contracts.tokenBridge.get(network, "Sui");
if (!token_bridge) { if (!token_bridge) {
throw new Error("Token bridge object ID is undefined"); throw new Error("Token bridge object ID is undefined");
} }
@ -44,8 +46,8 @@ export async function transferSui(
coins, coins,
coinType, coinType,
BigInt(amount), BigInt(amount),
dstChain, chainToChainId(dstChain),
tryNativeToUint8Array(dstAddress, dstChain) tryNativeToUint8Array(dstAddress, chainToChainId(dstChain))
); );
setMaxGasBudgetDevnet(network, tx); setMaxGasBudgetDevnet(network, tx);
const result = await executeTransactionBlock(signer, tx); const result = await executeTransactionBlock(signer, tx);

View File

@ -13,9 +13,10 @@ import {
} from "@mysten/sui.js"; } from "@mysten/sui.js";
import { DynamicFieldPage } from "@mysten/sui.js/dist/types/dynamic_fields"; import { DynamicFieldPage } from "@mysten/sui.js/dist/types/dynamic_fields";
import { NETWORKS } from "../../consts"; import { NETWORKS } from "../../consts";
import { Network } from "../../utils";
import { Payload, VAA, parse, serialiseVAA } from "../../vaa"; import { Payload, VAA, parse, serialiseVAA } from "../../vaa";
import { SuiRpcValidationError } from "./error"; import { SuiRpcValidationError } from "./error";
import { Network } from "@wormhole-foundation/sdk";
import { isValidSuiAddress } from "../../sdk/sui";
const UPGRADE_CAP_TYPE = "0x2::package::UpgradeCap"; const UPGRADE_CAP_TYPE = "0x2::package::UpgradeCap";
@ -207,7 +208,7 @@ export const getProvider = (
throw new Error("Must provide network or RPC to initialize provider"); throw new Error("Must provide network or RPC to initialize provider");
} }
rpc = rpc || NETWORKS[network!].sui.rpc; rpc = rpc || NETWORKS[network!].Sui.rpc;
if (!rpc) { if (!rpc) {
throw new Error(`No default RPC found for Sui ${network}`); throw new Error(`No default RPC found for Sui ${network}`);
} }
@ -235,7 +236,7 @@ export const getSigner = (
customPrivateKey?: string customPrivateKey?: string
): RawSigner => { ): RawSigner => {
const privateKey: string | undefined = const privateKey: string | undefined =
customPrivateKey || NETWORKS[network].sui.key; customPrivateKey || NETWORKS[network].Sui.key;
if (!privateKey) { if (!privateKey) {
throw new Error(`No private key found for Sui ${network}`); throw new Error(`No private key found for Sui ${network}`);
} }
@ -323,9 +324,6 @@ export const isSuiPublishEvent = <
event: T event: T
): event is K => event?.type === "published"; ): event is K => event?.type === "published";
export const isValidSuiAddress = (objectId: string): boolean =>
/^(0x)?[0-9a-f]{1,64}$/.test(objectId);
// todo(aki): this needs to correctly handle types such as // todo(aki): this needs to correctly handle types such as
// 0x2::dynamic_field::Field<0x3c6d386861470e6f9cb35f3c91f69e6c1f1737bd5d217ca06a15f582e1dc1ce3::state::MigrationControl, bool> // 0x2::dynamic_field::Field<0x3c6d386861470e6f9cb35f3c91f69e6c1f1737bd5d217ca06a15f582e1dc1ce3::state::MigrationControl, bool>
export const normalizeSuiType = (type: string): string => { export const normalizeSuiType = (type: string): string => {
@ -345,7 +343,7 @@ export const registerChain = async (
tokenBridgeStateObjectId: string, tokenBridgeStateObjectId: string,
transactionBlock?: TransactionBlock transactionBlock?: TransactionBlock
): Promise<TransactionBlock> => { ): Promise<TransactionBlock> => {
if (network === "DEVNET") { if (network === "Devnet") {
// Modify the VAA to only have 1 guardian signature // Modify the VAA to only have 1 guardian signature
// TODO: remove this when we can deploy the devnet core contract // TODO: remove this when we can deploy the devnet core contract
// deterministically with multiple guardians in the initial guardian set // deterministically with multiple guardians in the initial guardian set
@ -418,7 +416,7 @@ export const setMaxGasBudgetDevnet = (
network: Network, network: Network,
tx: TransactionBlock tx: TransactionBlock
) => { ) => {
if (network === "DEVNET") { if (network === "Devnet") {
// Avoid Error checking transaction input objects: GasBudgetTooHigh { gas_budget: 50000000000, max_budget: 10000000000 } // Avoid Error checking transaction input objects: GasBudgetTooHigh { gas_budget: 50000000000, max_budget: 10000000000 }
tx.setGasBudget(10000000000); tx.setGasBudget(10000000000);
} }

View File

@ -1,10 +1,3 @@
import { APTOS_DEPLOYER_ADDRESS_DEVNET } from "@certusone/wormhole-sdk";
import {
assertChain,
CHAIN_ID_APTOS,
coalesceChainId,
CONTRACTS,
} from "@certusone/wormhole-sdk/lib/esm/utils/consts";
import { BCS, FaucetClient } from "aptos"; import { BCS, FaucetClient } from "aptos";
import { spawnSync } from "child_process"; import { spawnSync } from "child_process";
import fs from "fs"; import fs from "fs";
@ -25,13 +18,23 @@ import {
RPC_OPTIONS, RPC_OPTIONS,
} from "../consts"; } from "../consts";
import { runCommand, VALIDATOR_OPTIONS } from "../startValidator"; import { runCommand, VALIDATOR_OPTIONS } from "../startValidator";
import { assertNetwork, checkBinary, evm_address, hex } from "../utils"; import { checkBinary, evm_address, getNetwork, hex } from "../utils";
import {
assertChain,
chainToChainId,
contracts,
toChain,
toChainId,
} from "@wormhole-foundation/sdk-base";
const APTOS_NODE_URL = "http://0.0.0.0:8080/v1"; const APTOS_NODE_URL = "http://0.0.0.0:8080/v1";
const APTOS_FAUCET_URL = "http://0.0.0.0:8081"; const APTOS_FAUCET_URL = "http://0.0.0.0:8081";
const README_URL = const README_URL =
"https://github.com/wormhole-foundation/wormhole/blob/main/aptos/README.md"; "https://github.com/wormhole-foundation/wormhole/blob/main/aptos/README.md";
export const APTOS_DEPLOYER_ADDRESS_DEVNET =
"277fa055b6a73c42c0662d5236c65c864ccbf2d4abd21f174a30c8b786eab84b";
interface Package { interface Package {
meta_file: string; meta_file: string;
mv_files: string[]; mv_files: string[];
@ -56,12 +59,11 @@ export const builder = (y: typeof yargs) =>
(yargs) => (yargs) =>
yargs.option("network", NETWORK_OPTIONS).option("rpc", RPC_OPTIONS), yargs.option("network", NETWORK_OPTIONS).option("rpc", RPC_OPTIONS),
async (argv) => { async (argv) => {
const network = argv.network.toUpperCase(); const network = getNetwork(argv.network);
assertNetwork(network);
const contract_address = evm_address( const contract_address = evm_address(
CONTRACTS[network].aptos.token_bridge contracts.tokenBridge(network, "Aptos")
); );
const rpc = argv.rpc ?? NETWORKS[network].aptos.rpc; const rpc = argv.rpc ?? NETWORKS[network].Aptos.rpc;
await callEntryFunc( await callEntryFunc(
network, network,
rpc, rpc,
@ -82,7 +84,7 @@ export const builder = (y: typeof yargs) =>
.option("chain-id", { .option("chain-id", {
describe: "Chain id", describe: "Chain id",
type: "number", type: "number",
default: CHAIN_ID_APTOS, default: chainToChainId("Aptos"),
demandOption: false, demandOption: false,
}) })
.option("governance-chain-id", { .option("governance-chain-id", {
@ -104,10 +106,11 @@ export const builder = (y: typeof yargs) =>
type: "string", type: "string",
}), }),
async (argv) => { async (argv) => {
const network = argv.network.toUpperCase(); const network = getNetwork(argv.network);
assertNetwork(network);
const contract_address = evm_address(CONTRACTS[network].aptos.core); const contract_address = evm_address(
contracts.coreBridge(network, "Aptos")
);
const guardian_addresses = argv["guardian-address"] const guardian_addresses = argv["guardian-address"]
.split(",") .split(",")
.map((address) => evm_address(address).substring(24)); .map((address) => evm_address(address).substring(24));
@ -127,7 +130,7 @@ export const builder = (y: typeof yargs) =>
BCS.bcsSerializeBytes(Buffer.from(governance_address, "hex")), BCS.bcsSerializeBytes(Buffer.from(governance_address, "hex")),
guardians_serializer.getBytes(), guardians_serializer.getBytes(),
]; ];
const rpc = argv.rpc ?? NETWORKS[network].aptos.rpc; const rpc = argv.rpc ?? NETWORKS[network].Aptos.rpc;
await callEntryFunc( await callEntryFunc(
network, network,
rpc, rpc,
@ -152,12 +155,11 @@ export const builder = (y: typeof yargs) =>
.option("rpc", RPC_OPTIONS) .option("rpc", RPC_OPTIONS)
.option("named-addresses", NAMED_ADDRESSES_OPTIONS), .option("named-addresses", NAMED_ADDRESSES_OPTIONS),
async (argv) => { async (argv) => {
const network = argv.network.toUpperCase(); const network = getNetwork(argv.network);
assertNetwork(network);
checkBinary("aptos", README_URL); checkBinary("aptos", README_URL);
const p = buildPackage(argv["package-dir"], argv["named-addresses"]); const p = buildPackage(argv["package-dir"], argv["named-addresses"]);
const b = serializePackage(p); const b = serializePackage(p);
const rpc = argv.rpc ?? NETWORKS[network].aptos.rpc; const rpc = argv.rpc ?? NETWORKS[network].Aptos.rpc;
await callEntryFunc( await callEntryFunc(
network, network,
rpc, rpc,
@ -188,21 +190,18 @@ export const builder = (y: typeof yargs) =>
.option("rpc", RPC_OPTIONS) .option("rpc", RPC_OPTIONS)
.option("named-addresses", NAMED_ADDRESSES_OPTIONS), .option("named-addresses", NAMED_ADDRESSES_OPTIONS),
async (argv) => { async (argv) => {
const network = argv.network.toUpperCase(); const network = getNetwork(argv.network);
assertNetwork(network);
checkBinary("aptos", README_URL); checkBinary("aptos", README_URL);
const p = buildPackage(argv["package-dir"], argv["named-addresses"]); const p = buildPackage(argv["package-dir"], argv["named-addresses"]);
const b = serializePackage(p); const b = serializePackage(p);
const seed = Buffer.from(argv["seed"], "ascii"); const seed = Buffer.from(argv["seed"], "ascii");
// TODO(csongor): use deployer address from sdk (when it's there) let module_name = APTOS_DEPLOYER_ADDRESS_DEVNET + "::deployer";
let module_name = if (network == "Testnet" || network == "Mainnet") {
"0x277fa055b6a73c42c0662d5236c65c864ccbf2d4abd21f174a30c8b786eab84b::deployer";
if (network == "TESTNET" || network == "MAINNET") {
module_name = module_name =
"0x0108bc32f7de18a5f6e1e7d6ee7aff9f5fc858d0d87ac0da94dd8d2a5d267d6b::deployer"; "0x0108bc32f7de18a5f6e1e7d6ee7aff9f5fc858d0d87ac0da94dd8d2a5d267d6b::deployer";
} }
const rpc = argv.rpc ?? NETWORKS[network].aptos.rpc; const rpc = argv.rpc ?? NETWORKS[network].Aptos.rpc;
await callEntryFunc( await callEntryFunc(
network, network,
rpc, rpc,
@ -226,13 +225,10 @@ export const builder = (y: typeof yargs) =>
}) })
.option("network", NETWORK_OPTIONS), .option("network", NETWORK_OPTIONS),
async (argv) => { async (argv) => {
const network = argv.network.toUpperCase(); const network = getNetwork(argv.network);
assertNetwork(network); const rpc = NETWORKS[network].Aptos.rpc;
const rpc = NETWORKS[network].aptos.rpc; let module_name = APTOS_DEPLOYER_ADDRESS_DEVNET + "::sender";
// TODO(csongor): use sdk address if (network == "Testnet" || network == "Mainnet") {
let module_name =
"0x277fa055b6a73c42c0662d5236c65c864ccbf2d4abd21f174a30c8b786eab84b::sender";
if (network == "TESTNET" || network == "MAINNET") {
module_name = module_name =
"0x0108bc32f7de18a5f6e1e7d6ee7aff9f5fc858d0d87ac0da94dd8d2a5d267d6b::sender"; "0x0108bc32f7de18a5f6e1e7d6ee7aff9f5fc858d0d87ac0da94dd8d2a5d267d6b::sender";
} }
@ -287,13 +283,12 @@ export const builder = (y: typeof yargs) =>
}) })
.option("network", NETWORK_OPTIONS), .option("network", NETWORK_OPTIONS),
async (argv) => { async (argv) => {
const network = argv.network.toUpperCase(); const network = getNetwork(argv.network);
assertNetwork(network); let address: string = contracts.tokenBridge(network, "Aptos");
let address = CONTRACTS[network].aptos.token_bridge;
if (address.startsWith("0x")) address = address.substring(2); if (address.startsWith("0x")) address = address.substring(2);
const token_bridge_address = Buffer.from(address, "hex"); const token_bridge_address = Buffer.from(address, "hex");
assertChain(argv.chain); assertChain(toChain(argv.chain));
const chain = coalesceChainId(argv.chain); const chain = toChainId(argv.chain);
const origin_address = Buffer.from( const origin_address = Buffer.from(
evm_address(argv["origin-address"]), evm_address(argv["origin-address"]),
"hex" "hex"
@ -343,12 +338,11 @@ export const builder = (y: typeof yargs) =>
.option("rpc", RPC_OPTIONS) .option("rpc", RPC_OPTIONS)
.option("named-addresses", NAMED_ADDRESSES_OPTIONS), .option("named-addresses", NAMED_ADDRESSES_OPTIONS),
async (argv) => { async (argv) => {
const network = argv.network.toUpperCase(); const network = getNetwork(argv.network);
assertNetwork(network);
checkBinary("aptos", README_URL); checkBinary("aptos", README_URL);
const p = buildPackage(argv["package-dir"], argv["named-addresses"]); const p = buildPackage(argv["package-dir"], argv["named-addresses"]);
const b = serializePackage(p); const b = serializePackage(p);
const rpc = argv.rpc ?? NETWORKS[network].aptos.rpc; const rpc = argv.rpc ?? NETWORKS[network].Aptos.rpc;
// TODO(csongor): use deployer address from sdk (when it's there) // TODO(csongor): use deployer address from sdk (when it's there)
const hash = await callEntryFunc( const hash = await callEntryFunc(
network, network,
@ -378,10 +372,9 @@ export const builder = (y: typeof yargs) =>
.option("network", NETWORK_OPTIONS) .option("network", NETWORK_OPTIONS)
.option("rpc", RPC_OPTIONS), .option("rpc", RPC_OPTIONS),
async (argv) => { async (argv) => {
const network = argv.network.toUpperCase(); const network = getNetwork(argv.network);
assertNetwork(network);
checkBinary("aptos", README_URL); checkBinary("aptos", README_URL);
const rpc = argv.rpc ?? NETWORKS[network].aptos.rpc; const rpc = argv.rpc ?? NETWORKS[network].Aptos.rpc;
// TODO(csongor): use deployer address from sdk (when it's there) // TODO(csongor): use deployer address from sdk (when it's there)
const hash = await callEntryFunc( const hash = await callEntryFunc(
network, network,

View File

@ -17,14 +17,14 @@
// //
import { Implementation__factory } from "@certusone/wormhole-sdk/lib/esm/ethers-contracts"; import { Implementation__factory } from "@certusone/wormhole-sdk/lib/esm/ethers-contracts";
import { CONTRACTS } from "@certusone/wormhole-sdk/lib/esm/utils/consts";
import { Other } from "@certusone/wormhole-sdk/lib/esm/vaa"; import { Other } from "@certusone/wormhole-sdk/lib/esm/vaa";
import axios from "axios"; import axios from "axios";
import { ethers } from "ethers"; import { ethers } from "ethers";
import yargs from "yargs"; import yargs from "yargs";
import { NETWORK_OPTIONS, NETWORKS } from "../consts"; import { NETWORK_OPTIONS, NETWORKS } from "../consts";
import { assertNetwork, Network } from "../utils";
import { parse, Payload, serialiseVAA, sign, Signature, VAA } from "../vaa"; import { parse, Payload, serialiseVAA, sign, Signature, VAA } from "../vaa";
import { contracts, Network } from "@wormhole-foundation/sdk-base";
import { getNetwork } from "../utils";
export const command = "edit-vaa"; export const command = "edit-vaa";
export const desc = "Edits or generates a VAA"; export const desc = "Edits or generates a VAA";
@ -102,8 +102,7 @@ export const builder = (y: typeof yargs) =>
export const handler = async ( export const handler = async (
argv: Awaited<ReturnType<typeof builder>["argv"]> argv: Awaited<ReturnType<typeof builder>["argv"]>
) => { ) => {
const network = argv.network.toUpperCase(); const network = getNetwork(argv.network);
assertNetwork(network);
let numSigs = 0; let numSigs = 0;
if (argv.signatures) { if (argv.signatures) {
@ -235,8 +234,8 @@ const getGuardianSet = async (
network: Network, network: Network,
guardianSetIndex: number guardianSetIndex: number
): Promise<string[]> => { ): Promise<string[]> => {
let n = NETWORKS[network].ethereum; let n = NETWORKS[network].Ethereum;
let contract_address = CONTRACTS[network].ethereum.core; let contract_address = contracts.coreBridge(network, "Ethereum");
if (contract_address === undefined) { if (contract_address === undefined) {
throw Error(`Unknown core contract on ${network} for ethereum`); throw Error(`Unknown core contract on ${network} for ethereum`);
} }

View File

@ -1,12 +1,3 @@
import {
assertChain,
assertEVMChain,
ChainName,
CHAINS,
CONTRACTS,
isEVMChain,
toChainName,
} from "@certusone/wormhole-sdk/lib/esm/utils/consts";
import { ethers } from "ethers"; import { ethers } from "ethers";
import { homedir } from "os"; import { homedir } from "os";
import yargs from "yargs"; import yargs from "yargs";
@ -18,7 +9,18 @@ import {
setStorageAt, setStorageAt,
} from "../evm"; } from "../evm";
import { runCommand, VALIDATOR_OPTIONS } from "../startValidator"; import { runCommand, VALIDATOR_OPTIONS } from "../startValidator";
import { assertNetwork, evm_address } from "../utils"; import {
assertEVMChain,
chainToChain,
evm_address,
getNetwork,
} from "../utils";
import {
assertChain,
chains,
contracts,
platformToChains,
} from "@wormhole-foundation/sdk-base";
export const command = "evm"; export const command = "evm";
export const desc = "EVM utilities"; export const desc = "EVM utilities";
@ -81,12 +83,7 @@ export const builder = function (y: typeof yargs) {
} }
) )
.command("chains", "Return all EVM chains", async (_) => { .command("chains", "Return all EVM chains", async (_) => {
console.log( console.log(...platformToChains("Evm"));
Object.values(CHAINS)
.map((id) => toChainName(id))
.filter((name) => isEVMChain(name))
.join(" ")
);
}) })
.command( .command(
"info", "info",
@ -96,7 +93,7 @@ export const builder = function (y: typeof yargs) {
.option("chain", { .option("chain", {
alias: "c", alias: "c",
describe: "Chain to query", describe: "Chain to query",
choices: Object.keys(CHAINS) as ChainName[], type: "string",
demandOption: true, demandOption: true,
} as const) } as const)
.option("module", { .option("module", {
@ -120,11 +117,9 @@ export const builder = function (y: typeof yargs) {
demandOption: false, demandOption: false,
}), }),
async (argv) => { async (argv) => {
const chain = argv.chain; const chain = chainToChain(argv.chain);
assertChain(chain);
assertEVMChain(chain); assertEVMChain(chain);
const network = argv.network.toUpperCase(); const network = getNetwork(argv.network);
assertNetwork(network);
const module = argv.module; const module = argv.module;
const rpc = argv.rpc ?? NETWORKS[network][chain].rpc; const rpc = argv.rpc ?? NETWORKS[network][chain].rpc;
if (argv["implementation-only"]) { if (argv["implementation-only"]) {
@ -163,7 +158,7 @@ export const builder = function (y: typeof yargs) {
alias: "a", alias: "a",
describe: "Core contract address", describe: "Core contract address",
type: "string", type: "string",
default: CONTRACTS.MAINNET.ethereum.core, default: contracts.coreBridge("Mainnet", "Ethereum"),
}) })
.option("guardian-address", { .option("guardian-address", {
alias: "g", alias: "g",
@ -180,7 +175,7 @@ export const builder = function (y: typeof yargs) {
}), }),
async (argv) => { async (argv) => {
const guardian_addresses = argv["guardian-address"].split(","); const guardian_addresses = argv["guardian-address"].split(",");
let rpc = argv.rpc ?? NETWORKS.DEVNET.ethereum.rpc; let rpc = argv.rpc ?? NETWORKS.Devnet.Ethereum.rpc;
await hijack_evm( await hijack_evm(
rpc, rpc,
argv["core-contract-address"], argv["core-contract-address"],

View File

@ -1,21 +1,11 @@
import { tryNativeToHexString } from "@certusone/wormhole-sdk/lib/esm/utils/array";
import {
assertChain,
ChainName,
CHAINS,
isCosmWasmChain,
isEVMChain,
toChainId,
} from "@certusone/wormhole-sdk/lib/esm/utils/consts";
import { fromBech32, toHex } from "@cosmjs/encoding"; import { fromBech32, toHex } from "@cosmjs/encoding";
import base58 from "bs58"; import base58 from "bs58";
import { sha3_256 } from "js-sha3"; import { sha3_256 } from "js-sha3";
import yargs from "yargs"; import yargs from "yargs";
import { GOVERNANCE_CHAIN, GOVERNANCE_EMITTER } from "../consts"; import { GOVERNANCE_CHAIN, GOVERNANCE_EMITTER } from "../consts";
import { evm_address } from "../utils"; import { chainToChain, evm_address } from "../utils";
import { import {
ContractUpgrade, ContractUpgrade,
impossible,
Payload, Payload,
PortalRegisterChain, PortalRegisterChain,
RecoverChainId, RecoverChainId,
@ -25,6 +15,13 @@ import {
VAA, VAA,
WormholeRelayerSetDefaultDeliveryProvider, WormholeRelayerSetDefaultDeliveryProvider,
} from "../vaa"; } from "../vaa";
import {
Chain,
assertChain,
chainToPlatform,
chains,
toChainId,
} from "@wormhole-foundation/sdk-base";
function makeVAA( function makeVAA(
emitterChain: number, emitterChain: number,
@ -68,7 +65,7 @@ export const builder = function (y: typeof yargs) {
.option("chain", { .option("chain", {
alias: "c", alias: "c",
describe: "Chain to register", describe: "Chain to register",
choices: Object.keys(CHAINS) as ChainName[], type: "string",
demandOption: true, demandOption: true,
} as const) } as const)
.option("contract-address", { .option("contract-address", {
@ -85,13 +82,13 @@ export const builder = function (y: typeof yargs) {
} as const), } as const),
(argv) => { (argv) => {
const module = argv["module"]; const module = argv["module"];
assertChain(argv.chain); const chain = chainToChain(argv.chain);
const payload: PortalRegisterChain<typeof module> = { const payload: PortalRegisterChain<typeof module> = {
module, module,
type: "RegisterChain", type: "RegisterChain",
chain: 0, chain: 0,
emitterChain: toChainId(argv.chain), emitterChain: toChainId(chain),
emitterAddress: parseAddress(argv.chain, argv["contract-address"]), emitterAddress: parseAddress(chain, argv["contract-address"]),
}; };
const vaa = makeVAA( const vaa = makeVAA(
GOVERNANCE_CHAIN, GOVERNANCE_CHAIN,
@ -111,7 +108,7 @@ export const builder = function (y: typeof yargs) {
.option("chain", { .option("chain", {
alias: "c", alias: "c",
describe: "Chain to upgrade", describe: "Chain to upgrade",
choices: Object.keys(CHAINS) as ChainName[], type: "string",
demandOption: true, demandOption: true,
} as const) } as const)
.option("contract-address", { .option("contract-address", {
@ -127,13 +124,13 @@ export const builder = function (y: typeof yargs) {
demandOption: true, demandOption: true,
} as const), } as const),
(argv) => { (argv) => {
assertChain(argv.chain); const chain = chainToChain(argv.chain);
const module = argv["module"]; const module = argv["module"];
const payload: ContractUpgrade = { const payload: ContractUpgrade = {
module, module,
type: "ContractUpgrade", type: "ContractUpgrade",
chain: toChainId(argv.chain), chain: toChainId(chain),
address: parseCodeAddress(argv.chain, argv["contract-address"]), address: parseCodeAddress(chain, argv["contract-address"]),
}; };
const vaa = makeVAA( const vaa = makeVAA(
GOVERNANCE_CHAIN, GOVERNANCE_CHAIN,
@ -152,7 +149,7 @@ export const builder = function (y: typeof yargs) {
.option("emitter-chain", { .option("emitter-chain", {
alias: "e", alias: "e",
describe: "Emitter chain of the VAA", describe: "Emitter chain of the VAA",
choices: Object.keys(CHAINS) as ChainName[], type: "string",
demandOption: true, demandOption: true,
} as const) } as const)
.option("emitter-address", { .option("emitter-address", {
@ -164,7 +161,7 @@ export const builder = function (y: typeof yargs) {
.option("chain", { .option("chain", {
alias: "c", alias: "c",
describe: "Token's chain", describe: "Token's chain",
choices: Object.keys(CHAINS) as ChainName[], type: "string",
demandOption: true, demandOption: true,
} as const) } as const)
.option("token-address", { .option("token-address", {
@ -192,15 +189,14 @@ export const builder = function (y: typeof yargs) {
demandOption: true, demandOption: true,
}), }),
(argv) => { (argv) => {
const emitter_chain = argv["emitter-chain"]; const emitter_chain = chainToChain(argv["emitter-chain"]);
assertChain(argv.chain); const chain = chainToChain(argv.chain);
assertChain(emitter_chain);
const payload: TokenBridgeAttestMeta = { const payload: TokenBridgeAttestMeta = {
module: "TokenBridge", module: "TokenBridge",
type: "AttestMeta", type: "AttestMeta",
chain: 0, chain: 0,
tokenAddress: parseAddress(argv.chain, argv["token-address"]), tokenAddress: parseAddress(chain, argv["token-address"]),
tokenChain: toChainId(argv.chain), tokenChain: toChainId(chain),
decimals: argv["decimals"], decimals: argv["decimals"],
symbol: argv["symbol"], symbol: argv["symbol"],
name: argv["name"], name: argv["name"],
@ -263,7 +259,7 @@ export const builder = function (y: typeof yargs) {
.option("chain", { .option("chain", {
alias: "c", alias: "c",
describe: "Chain of Wormhole Relayer contract", describe: "Chain of Wormhole Relayer contract",
choices: Object.keys(CHAINS), type: "string",
demandOption: true, demandOption: true,
} as const) } as const)
.option("delivery-provider-address", { .option("delivery-provider-address", {
@ -274,13 +270,13 @@ export const builder = function (y: typeof yargs) {
}); });
}, },
(argv) => { (argv) => {
assertChain(argv.chain); const chain = chainToChain(argv.chain);
const payload: WormholeRelayerSetDefaultDeliveryProvider = { const payload: WormholeRelayerSetDefaultDeliveryProvider = {
module: "WormholeRelayer", module: "WormholeRelayer",
type: "SetDefaultDeliveryProvider", type: "SetDefaultDeliveryProvider",
chain: toChainId(argv["chain"]), chain: toChainId(chain),
relayProviderAddress: parseAddress( relayProviderAddress: parseAddress(
argv["chain"], chain,
argv["delivery-provider-address"] argv["delivery-provider-address"]
), ),
}; };
@ -297,45 +293,43 @@ export const builder = function (y: typeof yargs) {
}; };
export const handler = () => {}; export const handler = () => {};
function parseAddress(chain: ChainName, address: string): string { function parseAddress(chain: Chain, address: string): string {
if (chain === "unset") { if (chainToPlatform(chain) === "Evm") {
throw Error("Chain unset");
} else if (isEVMChain(chain)) {
return "0x" + evm_address(address); return "0x" + evm_address(address);
} else if (isCosmWasmChain(chain)) { } else if (chainToPlatform(chain) === "Cosmwasm") {
return "0x" + toHex(fromBech32(address).data).padStart(64, "0"); return "0x" + toHex(fromBech32(address).data).padStart(64, "0");
} else if (chain === "solana" || chain === "pythnet") { } else if (chain === "Solana" || chain === "Pythnet") {
return "0x" + toHex(base58.decode(address)).padStart(64, "0"); return "0x" + toHex(base58.decode(address)).padStart(64, "0");
} else if (chain === "algorand") { } else if (chain === "Algorand") {
// TODO: is there a better native format for algorand? // TODO: is there a better native format for algorand?
return "0x" + evm_address(address); return "0x" + evm_address(address);
} else if (chain === "near") { } else if (chain === "Near") {
return "0x" + evm_address(address); return "0x" + evm_address(address);
} else if (chain === "sui") { } else if (chain === "Sui") {
return "0x" + evm_address(address); return "0x" + evm_address(address);
} else if (chain === "aptos") { } else if (chain === "Aptos") {
if (/^(0x)?[0-9a-fA-F]+$/.test(address)) { if (/^(0x)?[0-9a-fA-F]+$/.test(address)) {
return "0x" + evm_address(address); return "0x" + evm_address(address);
} }
return sha3_256(Buffer.from(address)); // address is hash of fully qualified type return sha3_256(Buffer.from(address)); // address is hash of fully qualified type
} else if (chain === "btc") { } else if (chain === "Btc") {
throw Error("btc is not supported yet"); throw Error("btc is not supported yet");
} else if (chain === "cosmoshub") { } else if (chain === "Cosmoshub") {
throw Error("cosmoshub is not supported yet"); throw Error("cosmoshub is not supported yet");
} else if (chain === "evmos") { } else if (chain === "Evmos") {
throw Error("evmos is not supported yet"); throw Error("evmos is not supported yet");
} else if (chain === "kujira") { } else if (chain === "Kujira") {
throw Error("kujira is not supported yet"); throw Error("kujira is not supported yet");
} else if (chain === "rootstock") { } else if (chain === "Rootstock") {
throw Error("rootstock is not supported yet"); throw Error("rootstock is not supported yet");
} else { } else {
impossible(chain); throw Error(`Unsupported chain: ${chain}`);
} }
} }
function parseCodeAddress(chain: ChainName, address: string): string { function parseCodeAddress(chain: Chain, address: string): string {
if (isCosmWasmChain(chain)) { if (chainToPlatform(chain) === "Cosmwasm") {
return "0x" + parseInt(address, 10).toString(16).padStart(64, "0"); return "0x" + parseInt(address, 10).toString(16).padStart(64, "0");
} else { } else {
return parseAddress(chain, address); return parseAddress(chain, address);

View File

@ -1,9 +1,6 @@
import {
assertChain,
coalesceChainId,
} from "@certusone/wormhole-sdk/lib/esm/utils/consts";
import yargs from "yargs"; import yargs from "yargs";
import { CHAIN_ID_OR_NAME_CHOICES } from "../../consts"; import { CHAIN_ID_OR_NAME_CHOICES } from "../../consts";
import { assertChain, toChain } from "@wormhole-foundation/sdk-base";
export const command = "chain-id <chain>"; export const command = "chain-id <chain>";
export const desc = export const desc =
@ -16,6 +13,6 @@ export const builder = (y: typeof yargs) => {
} as const); } as const);
}; };
export const handler = (argv: Awaited<ReturnType<typeof builder>["argv"]>) => { export const handler = (argv: Awaited<ReturnType<typeof builder>["argv"]>) => {
assertChain(argv.chain); assertChain(toChain(argv.chain));
console.log(coalesceChainId(argv.chain)); console.log(toChain(argv.chain));
}; };

View File

@ -1,13 +1,7 @@
import {
CHAINS,
ChainName,
assertChain,
} from "@certusone/wormhole-sdk/lib/esm/utils/consts";
import { relayer } from "@certusone/wormhole-sdk";
import yargs from "yargs"; import yargs from "yargs";
import { CONTRACTS } from "../../consts";
import { assertNetwork } from "../../utils";
import { impossible } from "../../vaa"; import { impossible } from "../../vaa";
import { contracts } from "@wormhole-foundation/sdk-base";
import { chainToChain, getNetwork } from "../../utils";
export const command = "contract <network> <chain> <module>"; export const command = "contract <network> <chain> <module>";
export const desc = "Print contract address"; export const desc = "Print contract address";
@ -20,7 +14,7 @@ export const builder = (y: typeof yargs) =>
} as const) } as const)
.positional("chain", { .positional("chain", {
describe: "Chain to query", describe: "Chain to query",
choices: Object.keys(CHAINS) as ChainName[], type: "string",
demandOption: true, demandOption: true,
} as const) } as const)
.positional("module", { .positional("module", {
@ -31,30 +25,27 @@ export const builder = (y: typeof yargs) =>
export const handler = async ( export const handler = async (
argv: Awaited<ReturnType<typeof builder>["argv"]> argv: Awaited<ReturnType<typeof builder>["argv"]>
) => { ) => {
const network = argv.network.toUpperCase(); const network = getNetwork(argv.network);
assertNetwork(network); const chain = chainToChain(argv.chain);
const chain = argv.chain;
assertChain(chain);
const module = argv["module"]; const module = argv["module"];
let addr: string | undefined; let addr: string | undefined;
switch (module) { switch (module) {
case "Core": case "Core":
addr = CONTRACTS[network][chain].core; addr = contracts.coreBridge.get(network, chain);
break; break;
case "NFTBridge": case "NFTBridge":
const addresses = CONTRACTS[network][chain]; addr = contracts.nftBridge.get(network, chain);
if (!("nft_bridge" in addresses)) { if (!addr) {
throw new Error(`NFTBridge not deployed on ${chain}`); throw new Error(`NFTBridge not deployed on ${chain}`);
} }
addr = addresses.nft_bridge;
break; break;
case "TokenBridge": case "TokenBridge":
addr = CONTRACTS[network][chain].token_bridge; addr = contracts.tokenBridge.get(network, chain);
break; break;
case "WormholeRelayer": case "WormholeRelayer":
addr = relayer.RELAYER_CONTRACTS[network][chain]?.wormholeRelayerAddress; addr = contracts.relayer.get(network, chain);
break; break;
default: default:
impossible(module); impossible(module);

View File

@ -1,10 +1,6 @@
import {
CHAINS,
ChainName,
assertChain,
} from "@certusone/wormhole-sdk/lib/esm/utils/consts";
import yargs from "yargs"; import yargs from "yargs";
import { getEmitterAddress } from "../../emitter"; import { getEmitterAddress } from "../../emitter";
import { assertChain, chains } from "@wormhole-foundation/sdk-base";
export const command = "emitter <chain> <address>"; export const command = "emitter <chain> <address>";
export const desc = "Print address in emitter address format"; export const desc = "Print address in emitter address format";
@ -13,7 +9,7 @@ export const builder = (y: typeof yargs) =>
.positional("chain", { .positional("chain", {
describe: "Chain to query", describe: "Chain to query",
type: "string", type: "string",
choices: Object.keys(CHAINS) as ChainName[], choices: chains,
demandOption: true, demandOption: true,
} as const) } as const)
.positional("address", { .positional("address", {

View File

@ -1,8 +1,9 @@
import { tryUint8ArrayToNative } from "@certusone/wormhole-sdk/lib/esm/utils";
import yargs from "yargs"; import yargs from "yargs";
import { getOriginalAsset } from "../../chains/generic"; import { getOriginalAsset } from "../../chains/generic";
import { CHAIN_ID_OR_NAME_CHOICES, RPC_OPTIONS } from "../../consts"; import { CHAIN_ID_OR_NAME_CHOICES, RPC_OPTIONS } from "../../consts";
import { assertNetwork } from "../../utils"; import { getNetwork } from "../../utils";
import { tryUint8ArrayToNative } from "../../sdk/array";
import { toChain } from "@wormhole-foundation/sdk-base";
export const command = "origin <chain> <address>"; export const command = "origin <chain> <address>";
export const desc = `Print the origin chain and address of the asset that corresponds to the given chain and address.`; export const desc = `Print the origin chain and address of the asset that corresponds to the given chain and address.`;
@ -32,12 +33,11 @@ export const handler = async (
const consoleWarnTemp = console.warn; const consoleWarnTemp = console.warn;
console.warn = () => {}; console.warn = () => {};
const network = argv.network.toUpperCase(); const network = getNetwork(argv.network);
assertNetwork(network);
const res = await getOriginalAsset(argv.chain, network, argv.address); const res = await getOriginalAsset(argv.chain, network, argv.address);
console.log({ console.log({
...res, ...res,
assetAddress: tryUint8ArrayToNative(res.assetAddress, res.chainId), assetAddress: tryUint8ArrayToNative(res.assetAddress, toChain(res.chainId)),
}); });
console.warn = consoleWarnTemp; console.warn = consoleWarnTemp;

View File

@ -3,16 +3,17 @@
// is defined in the consts.ts file in the SDK (to verify that all chains // are properly registered.) // is defined in the consts.ts file in the SDK (to verify that all chains // are properly registered.)
import yargs from "yargs"; import yargs from "yargs";
import {
assertChain,
ChainName,
CHAINS,
Contracts,
CONTRACTS,
isEVMChain,
isTerraChain,
} from "@certusone/wormhole-sdk/lib/esm/utils/consts";
import { getEmitterAddress } from "../../emitter"; import { getEmitterAddress } from "../../emitter";
import {
Network,
assertChain,
chainToPlatform,
chains,
contracts,
toChain,
} from "@wormhole-foundation/sdk-base";
import { chainToChain, getNetwork } from "../../utils";
import { Chain } from "@wormhole-foundation/sdk";
export const command = "registrations <network> <chain> <module>"; export const command = "registrations <network> <chain> <module>";
export const desc = "Print chain registrations"; export const desc = "Print chain registrations";
@ -25,7 +26,7 @@ export const builder = (y: typeof yargs) => {
} as const) } as const)
.positional("chain", { .positional("chain", {
describe: "Chain to query", describe: "Chain to query",
choices: Object.keys(CHAINS) as ChainName[], type: "string",
demandOption: true, demandOption: true,
} as const) } as const)
.positional("module", { .positional("module", {
@ -45,43 +46,39 @@ export const builder = (y: typeof yargs) => {
export const handler = async ( export const handler = async (
argv: Awaited<ReturnType<typeof builder>["argv"]> argv: Awaited<ReturnType<typeof builder>["argv"]>
) => { ) => {
assertChain(argv.chain); const chain = chainToChain(argv.chain);
const chain = argv.chain; const network = getNetwork(argv.network);
const network = argv.network.toUpperCase();
if (network !== "MAINNET" && network !== "TESTNET" && network !== "DEVNET") {
throw Error(`Unknown network: ${network}`);
}
const module = argv.module; const module = argv.module;
if (module !== "TokenBridge" && module !== "NFTBridge") { if (module !== "TokenBridge" && module !== "NFTBridge") {
throw Error(`Module must be TokenBridge or NFTBridge`); throw Error(`Module must be TokenBridge or NFTBridge`);
} }
let results: object; let results: object;
if (chain === "solana") { if (chain === "Solana") {
const solana = require("../../solana"); const solana = require("../../solana");
results = await solana.queryRegistrationsSolana(network, module); results = await solana.queryRegistrationsSolana(network, module);
} else if (isEVMChain(chain)) { } else if (chainToPlatform(chain) === "Evm") {
const evm = require("../../evm"); const evm = require("../../evm");
results = await evm.queryRegistrationsEvm(network, chain, module); results = await evm.queryRegistrationsEvm(network, chain, module);
} else if (isTerraChain(chain) || chain === "xpla") { } else if (chain === "Terra" || chain === "Terra2" || chain === "Xpla") {
const terra = require("../../terra"); const terra = require("../../terra");
results = await terra.queryRegistrationsTerra(network, chain, module); results = await terra.queryRegistrationsTerra(network, chain, module);
} else if (chain === "injective") { } else if (chain === "Injective") {
const injective = require("../../injective"); const injective = require("../../injective");
results = await injective.queryRegistrationsInjective(network, module); results = await injective.queryRegistrationsInjective(network, module);
} else if (chain === "sei") { } else if (chain === "Sei") {
const sei = require("../../chains/sei/registrations"); const sei = require("../../chains/sei/registrations");
results = await sei.queryRegistrationsSei(network, module); results = await sei.queryRegistrationsSei(network, module);
} else if (chain === "sui") { } else if (chain === "Sui") {
const sui = require("../../chains/sui/registrations"); const sui = require("../../chains/sui/registrations");
results = await sui.queryRegistrationsSui(network, module); results = await sui.queryRegistrationsSui(network, module);
} else if (chain === "aptos") { } else if (chain === "Aptos") {
const aptos = require("../../aptos"); const aptos = require("../../aptos");
results = await aptos.queryRegistrationsAptos(network, module); results = await aptos.queryRegistrationsAptos(network, module);
} else { } else {
throw Error(`Command not supported for chain ${chain}`); throw Error(`Command not supported for chain ${chain}`);
} }
if (argv["verify"]) { if (argv["verify"]) {
verifyRegistrations(network, chain as string, module, results); verifyRegistrations(network, chain, module, results);
} else { } else {
console.log(results); console.log(results);
} }
@ -89,8 +86,8 @@ export const handler = async (
// verifyRegistrations takes the results returned above and verifies them against the expected values in the consts file. // verifyRegistrations takes the results returned above and verifies them against the expected values in the consts file.
async function verifyRegistrations( async function verifyRegistrations(
network: "MAINNET" | "TESTNET" | "DEVNET", network: Network,
chain: string, chain: Chain,
module: "NFTBridge" | "TokenBridge", module: "NFTBridge" | "TokenBridge",
input: Object input: Object
) { ) {
@ -104,25 +101,21 @@ async function verifyRegistrations(
// Loop over the chains and make sure everything is in our input, and the values match. // Loop over the chains and make sure everything is in our input, and the values match.
const results: { [key: string]: string } = {}; const results: { [key: string]: string } = {};
for (const chainStr in CHAINS) { for (const chainStr of chains) {
const thisChain = chainStr as ChainName; const thisChain = toChain(chainStr);
if (thisChain === "unset" || thisChain === chain) { if (thisChain === chain) {
continue; continue;
} }
const contracts: Contracts = CONTRACTS[network][thisChain];
let expectedAddr: string | undefined; let expectedAddr: string | undefined;
if (module === "TokenBridge") { if (module === "TokenBridge") {
expectedAddr = contracts.token_bridge; expectedAddr = contracts.tokenBridge.get(network, thisChain);
} else { } else {
expectedAddr = contracts.nft_bridge; expectedAddr = contracts.nftBridge.get(network, thisChain);
} }
if (expectedAddr !== undefined) { if (expectedAddr !== undefined) {
expectedAddr = await getEmitterAddress( expectedAddr = await getEmitterAddress(thisChain, expectedAddr);
thisChain as ChainName,
expectedAddr
);
if (!expectedAddr.startsWith("0x")) { if (!expectedAddr.startsWith("0x")) {
expectedAddr = "0x" + expectedAddr; expectedAddr = "0x" + expectedAddr;
} }

View File

@ -1,11 +1,6 @@
import {
CHAINS,
ChainName,
assertChain,
} from "@certusone/wormhole-sdk/lib/esm/utils/consts";
import yargs from "yargs"; import yargs from "yargs";
import { NETWORKS } from "../../consts"; import { NETWORKS } from "../../consts";
import { assertNetwork } from "../../utils"; import { chainToChain, getNetwork } from "../../utils";
export const command = "rpc <network> <chain>"; export const command = "rpc <network> <chain>";
export const desc = "Print RPC address"; export const desc = "Print RPC address";
@ -18,14 +13,12 @@ export const builder = (y: typeof yargs) =>
} as const) } as const)
.positional("chain", { .positional("chain", {
describe: "Chain to query", describe: "Chain to query",
choices: Object.keys(CHAINS) as ChainName[], type: "string",
demandOption: true, demandOption: true,
} as const); } as const);
export const handler = async ( export const handler = async (
argv: Awaited<ReturnType<typeof builder>["argv"]> argv: Awaited<ReturnType<typeof builder>["argv"]>
) => { ) => {
assertChain(argv.chain); const network = getNetwork(argv.network);
const network = argv.network.toUpperCase(); console.log(NETWORKS[network][chainToChain(argv.chain)].rpc);
assertNetwork(network);
console.log(NETWORKS[network][argv.chain].rpc);
}; };

View File

@ -1,8 +1,8 @@
import { assertChain } from "@certusone/wormhole-sdk/lib/esm/utils/consts"; import { assertChain } from "@certusone/wormhole-sdk/lib/esm/utils/consts";
import yargs from "yargs"; import yargs from "yargs";
import { getWrappedAssetAddress } from "../../chains/generic/getWrappedAssetAddress"; import { getWrappedAssetAddress } from "../../chains/generic/getWrappedAssetAddress";
import { CHAIN_ID_OR_NAME_CHOICES, RPC_OPTIONS } from "../../consts"; import { RPC_OPTIONS } from "../../consts";
import { assertNetwork } from "../../utils"; import { chainToChain, getNetwork } from "../../utils";
export const command = "wrapped <origin-chain> <origin-address> <target-chain>"; export const command = "wrapped <origin-chain> <origin-address> <target-chain>";
export const desc = export const desc =
@ -11,7 +11,7 @@ export const builder = (y: typeof yargs) =>
y y
.positional("origin-chain", { .positional("origin-chain", {
describe: "Chain that wrapped asset came from", describe: "Chain that wrapped asset came from",
choices: CHAIN_ID_OR_NAME_CHOICES, type: "string",
demandOption: true, demandOption: true,
} as const) } as const)
.positional("origin-address", { .positional("origin-address", {
@ -21,7 +21,7 @@ export const builder = (y: typeof yargs) =>
}) })
.positional("target-chain", { .positional("target-chain", {
describe: "Chain to query for wrapped asset address", describe: "Chain to query for wrapped asset address",
choices: CHAIN_ID_OR_NAME_CHOICES, type: "string",
demandOption: true, demandOption: true,
} as const) } as const)
.option("network", { .option("network", {
@ -42,14 +42,13 @@ export const handler = async (
const consoleWarnTemp = console.warn; const consoleWarnTemp = console.warn;
console.warn = () => {}; console.warn = () => {};
const originChain = argv["origin-chain"]; const originChain = chainToChain(argv["origin-chain"]);
const originAddress = argv["origin-address"]; const originAddress = argv["origin-address"];
const targetChain = argv["target-chain"]; const targetChain = chainToChain(argv["target-chain"]);
const network = argv.network.toUpperCase(); const network = getNetwork(argv.network);
assertChain(originChain); assertChain(originChain);
assertChain(targetChain); assertChain(targetChain);
assertNetwork(network);
console.log( console.log(
await getWrappedAssetAddress( await getWrappedAssetAddress(

View File

@ -4,8 +4,9 @@ import { Account, KeyPair, connect } from "near-api-js";
import { InMemoryKeyStore } from "near-api-js/lib/key_stores"; import { InMemoryKeyStore } from "near-api-js/lib/key_stores";
import { parseSeedPhrase } from "near-seed-phrase"; import { parseSeedPhrase } from "near-seed-phrase";
import yargs from "yargs"; import yargs from "yargs";
import { CONTRACTS, NETWORKS, NETWORK_OPTIONS, RPC_OPTIONS } from "../consts"; import { NETWORKS, NETWORK_OPTIONS, RPC_OPTIONS } from "../consts";
import { assertNetwork } from "../utils"; import { contracts } from "@wormhole-foundation/sdk-base";
import { getNetwork } from "../utils";
// Near utilities // Near utilities
export const command = "near"; export const command = "near";
@ -55,14 +56,12 @@ export const builder = function (y: typeof yargs) {
demandOption: true, demandOption: true,
}), }),
async (argv) => { async (argv) => {
const network = argv.network.toUpperCase(); const network = getNetwork(argv.network);
assertNetwork(network);
const contracts = CONTRACTS[network].near;
const { const {
rpc: defaultRpc, rpc: defaultRpc,
key: defaultKey, key: defaultKey,
networkId, networkId,
} = NETWORKS[network].near; } = NETWORKS[network].Near;
const key = const key =
argv.key ?? argv.key ??
@ -80,12 +79,12 @@ export const builder = function (y: typeof yargs) {
let target = argv.target; let target = argv.target;
if (!argv.target && argv.module) { if (!argv.target && argv.module) {
if (argv.module === "Core") { if (argv.module === "Core") {
target = contracts.core; target = contracts.coreBridge(network, "Near");
console.log("Setting target to core"); console.log("Setting target to core");
} }
if (argv.module === "TokenBridge") { if (argv.module === "TokenBridge") {
target = contracts.token_bridge; target = contracts.tokenBridge(network, "Near");
console.log("Setting target to token_bridge"); console.log("Setting target to token_bridge");
} }
} }
@ -125,14 +124,12 @@ export const builder = function (y: typeof yargs) {
demandOption: true, demandOption: true,
}), }),
async (argv) => { async (argv) => {
const network = argv.network.toUpperCase(); const network = getNetwork(argv.network);
assertNetwork(network);
const contracts = CONTRACTS[network].near;
const { const {
rpc: defaultRpc, rpc: defaultRpc,
key: defaultKey, key: defaultKey,
networkId, networkId,
} = NETWORKS[network].near; } = NETWORKS[network].Near;
const key = const key =
argv.key ?? argv.key ??
@ -150,12 +147,12 @@ export const builder = function (y: typeof yargs) {
let target = argv.target; let target = argv.target;
if (!argv.target && argv.module) { if (!argv.target && argv.module) {
if (argv.module === "Core") { if (argv.module === "Core") {
target = contracts.core; target = contracts.coreBridge(network, "Near");
console.log("Setting target to core"); console.log("Setting target to core");
} }
if (argv.module === "TokenBridge") { if (argv.module === "TokenBridge") {
target = contracts.token_bridge; target = contracts.tokenBridge(network, "Near");
console.log("Setting target to token_bridge"); console.log("Setting target to token_bridge");
} }
} }

View File

@ -1,14 +1,9 @@
import { import yargs from "yargs";
CHAINS,
ChainName,
assertChain,
} from "@certusone/wormhole-sdk/lib/esm/utils/consts";
import { relayer, Network } from "@certusone/wormhole-sdk";
import yargs, { string } from "yargs";
import { CONTRACTS, NETWORKS } from "../consts";
import { assertNetwork } from "../utils";
import { impossible } from "../vaa";
import { ethers } from "ethers"; import { ethers } from "ethers";
import { NETWORKS } from "../consts";
import { chainToChain, getNetwork } from "../utils";
import { Chain, assertChain, contracts } from "@wormhole-foundation/sdk-base";
import { relayer } from "@certusone/wormhole-sdk";
export const command = "status <network> <chain> <tx>"; export const command = "status <network> <chain> <tx>";
export const desc = export const desc =
@ -22,7 +17,7 @@ export const builder = (y: typeof yargs) =>
} as const) } as const)
.positional("chain", { .positional("chain", {
describe: "Source chain", describe: "Source chain",
choices: Object.keys(CHAINS) as ChainName[], type: "string",
demandOption: true, demandOption: true,
} as const) } as const)
.positional("tx", { .positional("tx", {
@ -33,34 +28,32 @@ export const builder = (y: typeof yargs) =>
export const handler = async ( export const handler = async (
argv: Awaited<ReturnType<typeof builder>["argv"]> argv: Awaited<ReturnType<typeof builder>["argv"]>
) => { ) => {
const network = argv.network.toUpperCase(); const network = getNetwork(argv.network);
assertNetwork(network); const chain = chainToChain(argv.chain);
const chain = argv.chain;
assertChain(chain); assertChain(chain);
const addr = const addr = contracts.relayer.get(network, chain);
relayer.RELAYER_CONTRACTS[network][chain]?.wormholeRelayerAddress;
if (!addr) { if (!addr) {
throw new Error(`Wormhole Relayer not deployed on ${chain} in ${network}`); throw new Error(`Wormhole Relayer not deployed on ${chain} in ${network}`);
} }
const sourceRPC = NETWORKS[network as Network][chain as ChainName].rpc; const sourceRPC = NETWORKS[network][chain].rpc;
const sourceChainProvider = new ethers.providers.JsonRpcProvider(sourceRPC); const sourceChainProvider = new ethers.providers.JsonRpcProvider(sourceRPC);
const targetChainProviders = new Map<ChainName, ethers.providers.Provider>(); const targetChainProviders = new Map<Chain, ethers.providers.Provider>();
for (const key in NETWORKS[network]) { for (const key in NETWORKS[network]) {
targetChainProviders.set( targetChainProviders.set(
key as ChainName, key as Chain,
new ethers.providers.JsonRpcProvider( new ethers.providers.JsonRpcProvider(NETWORKS[network][key as Chain].rpc)
NETWORKS[network as Network][key as ChainName].rpc
)
); );
} }
const info = await relayer.getWormholeRelayerInfo(chain, argv.tx, { // TODO: Convert this over to sdkv2
environment: network, // const info = await relayer.getWormholeRelayerInfo(chain, argv.tx, {
sourceChainProvider, // environment: network,
targetChainProviders, // sourceChainProvider,
}); // targetChainProviders,
// });
// console.log(relayer.stringifyWormholeRelayerInfo(info));
console.log(relayer.stringifyWormholeRelayerInfo(info)); console.log("Not implemented");
}; };

View File

@ -1,15 +1,3 @@
import {
assertChain,
ChainId,
ChainName,
CHAINS,
coalesceChainName,
Contracts,
CONTRACTS,
isEVMChain,
isTerraChain,
toChainName,
} from "@certusone/wormhole-sdk/lib/esm/utils/consts";
import yargs from "yargs"; import yargs from "yargs";
import { execute_algorand } from "../algorand"; import { execute_algorand } from "../algorand";
import { execute_aptos } from "../aptos"; import { execute_aptos } from "../aptos";
@ -21,11 +9,22 @@ import { execute_injective } from "../injective";
import { execute_near } from "../near"; import { execute_near } from "../near";
import { execute_solana } from "../solana"; import { execute_solana } from "../solana";
import { execute_terra } from "../terra"; import { execute_terra } from "../terra";
import { assertNetwork } from "../utils";
import { assertKnownPayload, impossible, parse, Payload, VAA } from "../vaa"; import { assertKnownPayload, impossible, parse, Payload, VAA } from "../vaa";
import { execute_xpla } from "../xpla"; import { execute_xpla } from "../xpla";
import { NETWORKS } from "../consts"; import { NETWORKS } from "../consts";
import { Network } from "../utils"; import { chainToChain, getNetwork } from "../utils";
import {
Chain,
Network,
PlatformToChains,
assertChain,
assertChainId,
chainIdToChain,
chainToPlatform,
chains,
contracts,
toChain,
} from "@wormhole-foundation/sdk";
export const command = "submit <vaa>"; export const command = "submit <vaa>";
export const desc = "Execute a VAA"; export const desc = "Execute a VAA";
@ -39,7 +38,7 @@ export const builder = (y: typeof yargs) =>
.option("chain", { .option("chain", {
alias: "c", alias: "c",
describe: "chain name", describe: "chain name",
choices: Object.keys(CHAINS) as ChainName[], type: "string",
demandOption: false, demandOption: false,
} as const) } as const)
.option("network", NETWORK_OPTIONS) .option("network", NETWORK_OPTIONS)
@ -72,8 +71,7 @@ export const handler = async (
assertKnownPayload(parsed_vaa); assertKnownPayload(parsed_vaa);
console.log(parsed_vaa.payload); console.log(parsed_vaa.payload);
const network = argv.network.toUpperCase(); const network = getNetwork(argv.network);
assertNetwork(network);
if (argv["all-chains"]) { if (argv["all-chains"]) {
if (argv.rpc) { if (argv.rpc) {
@ -104,22 +102,34 @@ export const handler = async (
// get VAA chain // get VAA chain
const vaa_chain_id = const vaa_chain_id =
"chain" in parsed_vaa.payload ? parsed_vaa.payload.chain : 0; "chain" in parsed_vaa.payload ? parsed_vaa.payload.chain : 0;
assertChain(vaa_chain_id);
const vaa_chain = toChainName(vaa_chain_id); // if vaa_chain_id is 0, it means the chain is not specified in the VAA.
// We don't have a notion of an unsupported chain, so we don't want to just assert.
let vaa_chain;
if (vaa_chain_id !== 0) {
assertChainId(vaa_chain_id);
vaa_chain = chainIdToChain(vaa_chain_id);
}
// get chain from command line arg // get chain from command line arg
const cli_chain = argv.chain; const cli_chain = argv.chain ? chainToChain(argv.chain) : argv.chain;
let chain: ChainName; let chain: Chain;
if (cli_chain !== undefined) { if (cli_chain !== undefined) {
assertChain(cli_chain); assertChain(cli_chain);
if (vaa_chain !== "unset" && cli_chain !== vaa_chain) { if (vaa_chain && cli_chain !== vaa_chain) {
throw Error( throw Error(
`Specified target chain (${cli_chain}) does not match VAA target chain (${vaa_chain})` `Specified target chain (${cli_chain}) does not match VAA target chain (${vaa_chain})`
); );
} }
chain = coalesceChainName(cli_chain); chain = toChain(cli_chain);
} else { } else {
if (!vaa_chain) {
throw Error(
`VAA does not specify a target chain and one was not provided, please specify one with --chain or -c`
);
}
assertChain(vaa_chain);
chain = vaa_chain; chain = vaa_chain;
} }
@ -139,75 +149,59 @@ async function executeSubmit(
parsedVaa: VAA<Payload>, parsedVaa: VAA<Payload>,
buf: Buffer, buf: Buffer,
network: Network, network: Network,
chain: ChainName, chain: Chain,
rpc: string | undefined, rpc: string | undefined,
contractAddress: string | undefined contractAddress: string | undefined
) { ) {
if (chain === "unset") { if (chainToPlatform(chain) === "Evm") {
throw Error(
"This VAA does not specify the target chain, please provide it by hand using the '--chain' flag."
);
} else if (isEVMChain(chain)) {
await execute_evm( await execute_evm(
parsedVaa.payload, parsedVaa.payload,
buf, buf,
network, network,
chain, chain as PlatformToChains<"Evm">,
contractAddress, contractAddress,
rpc rpc
); );
} else if (isTerraChain(chain)) { } else if (chain === "Terra" || chain === "Terra2") {
await execute_terra(parsedVaa.payload, buf, network, chain); await execute_terra(parsedVaa.payload, buf, network, chain);
} else if (chain === "solana" || chain === "pythnet") { } else if (chain === "Solana" || chain === "Pythnet") {
await execute_solana(parsedVaa, buf, network, chain); await execute_solana(parsedVaa, buf, network, chain);
} else if (chain === "algorand") { } else if (chain === "Algorand") {
await execute_algorand( await execute_algorand(
parsedVaa.payload, parsedVaa.payload,
new Uint8Array(Buffer.from(vaaHex, "hex")), new Uint8Array(Buffer.from(vaaHex, "hex")),
network network
); );
} else if (chain === "near") { } else if (chain === "Near") {
await execute_near(parsedVaa.payload, vaaHex, network); await execute_near(parsedVaa.payload, vaaHex, network);
} else if (chain === "injective") { } else if (chain === "Injective") {
await execute_injective(parsedVaa.payload, buf, network); await execute_injective(parsedVaa.payload, buf, network);
} else if (chain === "xpla") { } else if (chain === "Xpla") {
await execute_xpla(parsedVaa.payload, buf, network); await execute_xpla(parsedVaa.payload, buf, network);
} else if (chain === "sei") { } else if (chain === "Sei") {
await submitSei(parsedVaa.payload, buf, network, rpc); await submitSei(parsedVaa.payload, buf, network, rpc);
} else if (chain === "osmosis") { } else if (chain === "Osmosis") {
throw Error("OSMOSIS is not supported yet"); throw Error("OSMOSIS is not supported yet");
} else if (chain === "sui") { } else if (chain === "Sui") {
await submitSui(parsedVaa.payload, buf, network, rpc); await submitSui(parsedVaa.payload, buf, network, rpc);
} else if (chain === "aptos") { } else if (chain === "Aptos") {
await execute_aptos(parsedVaa.payload, buf, network, contractAddress, rpc); await execute_aptos(parsedVaa.payload, buf, network, contractAddress, rpc);
} else if (chain === "wormchain") { } else if (chain === "Wormchain") {
throw Error("Wormchain is not supported yet"); throw Error("Wormchain is not supported yet");
} else if (chain === "btc") { } else if (chain === "Btc") {
throw Error("btc is not supported yet"); throw Error("btc is not supported yet");
} else if (chain === "cosmoshub") { } else if (chain === "Cosmoshub") {
throw Error("Cosmoshub is not supported yet"); throw Error("Cosmoshub is not supported yet");
} else if (chain === "evmos") { } else if (chain === "Evmos") {
throw Error("Evmos is not supported yet"); throw Error("Evmos is not supported yet");
} else if (chain === "kujira") { } else if (chain === "Kujira") {
throw Error("kujira is not supported yet"); throw Error("kujira is not supported yet");
} else if (chain === "neutron") { } else if (chain === "Neutron") {
throw Error("neutron is not supported yet"); throw Error("neutron is not supported yet");
} else if (chain === "celestia") { } else if (chain === "Celestia") {
throw Error("celestia is not supported yet"); throw Error("celestia is not supported yet");
} else if (chain === "stargaze") {
throw Error("stargaze is not supported yet");
} else if (chain === "seda") {
throw Error("seda is not supported yet");
} else if (chain === "dymension") {
throw Error("dymension is not supported yet");
} else if (chain === "provenance") {
throw Error("provenance is not supported yet");
} else if (chain === "rootstock") {
throw Error("rootstock is not supported yet");
} else { } else {
// If you get a type error here, hover over `chain`'s type and it tells you throw new Error(`Unsupported chain: ${chain}`);
// which cases are not handled
impossible(chain);
} }
} }
@ -217,24 +211,19 @@ async function submitToAll(
buf: Buffer, buf: Buffer,
network: Network network: Network
) { ) {
let skip_chain: ChainName = "unset"; let skip_chain: Chain;
if (parsedVaa.payload.type === "RegisterChain") { if (parsedVaa.payload.type === "RegisterChain") {
skip_chain = toChainName(parsedVaa.payload.emitterChain as ChainId); skip_chain = toChain(parsedVaa.payload.emitterChain);
} else if (parsedVaa.payload.type === "AttestMeta") { } else if (parsedVaa.payload.type === "AttestMeta") {
skip_chain = toChainName(parsedVaa.payload.tokenChain as ChainId); skip_chain = toChain(parsedVaa.payload.tokenChain);
} else { } else {
throw Error( throw Error(
`Invalid VAA payload type (${parsedVaa.payload.type}), only "RegisterChain" and "AttestMeta" are supported with --all-chains` `Invalid VAA payload type (${parsedVaa.payload.type}), only "RegisterChain" and "AttestMeta" are supported with --all-chains`
); );
} }
for (const chainStr in CHAINS) { for (const chain of chains) {
let chain = chainStr as ChainName;
if (chain === "unset") {
continue;
}
const n = NETWORKS[network][chain]; const n = NETWORKS[network][chain];
const contracts: Contracts = CONTRACTS[network][chain];
if (chain == skip_chain) { if (chain == skip_chain) {
console.log(`Skipping ${chain} because it's the origin chain`); console.log(`Skipping ${chain} because it's the origin chain`);
continue; continue;
@ -243,15 +232,11 @@ async function submitToAll(
console.log(`Skipping ${chain} because the rpc is not defined`); console.log(`Skipping ${chain} because the rpc is not defined`);
continue; continue;
} }
if (!contracts) {
console.log(
`Skipping ${chain} because the contract entry is not defined`
);
return true;
}
if ( if (
(parsedVaa.payload.module === "TokenBridge" && !contracts.token_bridge) || (parsedVaa.payload.module === "TokenBridge" &&
(parsedVaa.payload.module === "NFTBridge" && !contracts.nft_bridge) !contracts.tokenBridge.get(network, chain)) ||
(parsedVaa.payload.module === "NFTBridge" &&
!contracts.nftBridge.get(network, chain))
) { ) {
console.log(`Skipping ${chain} because the contract is not defined`); console.log(`Skipping ${chain} because the contract is not defined`);
continue; continue;

View File

@ -1,14 +1,10 @@
import path from "path"; import path from "path";
import yargs from "yargs"; import yargs from "yargs";
import { buildCoin, getProvider } from "../../chains/sui"; import { buildCoin, getProvider } from "../../chains/sui";
import { import { NETWORKS, NETWORK_OPTIONS, RPC_OPTIONS } from "../../consts";
CONTRACTS, import { checkBinary, getNetwork } from "../../utils";
NETWORKS,
NETWORK_OPTIONS,
RPC_OPTIONS,
} from "../../consts";
import { assertNetwork, checkBinary } from "../../utils";
import { YargsAddCommandsFn } from "../Yargs"; import { YargsAddCommandsFn } from "../Yargs";
import { contracts } from "@wormhole-foundation/sdk";
const README_URL = const README_URL =
"https://github.com/wormhole-foundation/wormhole/blob/main/sui/README.md"; "https://github.com/wormhole-foundation/wormhole/blob/main/sui/README.md";
@ -58,17 +54,16 @@ export const addBuildCommands: YargsAddCommandsFn = (y: typeof yargs) =>
async (argv) => { async (argv) => {
checkBinary("sui", README_URL); checkBinary("sui", README_URL);
const network = argv.network.toUpperCase(); const network = getNetwork(argv.network);
assertNetwork(network);
const decimals = argv["decimals"]; const decimals = argv["decimals"];
const version = argv["version-struct"]; const version = argv["version-struct"];
const packagePath = const packagePath =
argv["package-path"] ?? argv["package-path"] ??
path.resolve(__dirname, "../../../../../sui/examples"); path.resolve(__dirname, "../../../../../sui/examples");
const coreBridgeStateObjectId = const coreBridgeStateObjectId =
argv["wormhole-state"] ?? CONTRACTS[network].sui.core; argv["wormhole-state"] ?? contracts.coreBridge(network, "Sui");
const tokenBridgeStateObjectId = const tokenBridgeStateObjectId =
argv["token-bridge-state"] ?? CONTRACTS[network].sui.token_bridge; argv["token-bridge-state"] ?? contracts.tokenBridge(network, "Sui");
if (!coreBridgeStateObjectId) { if (!coreBridgeStateObjectId) {
throw new Error( throw new Error(
@ -84,7 +79,7 @@ export const addBuildCommands: YargsAddCommandsFn = (y: typeof yargs) =>
const provider = getProvider( const provider = getProvider(
network, network,
argv.rpc ?? NETWORKS[network].sui.rpc argv.rpc ?? NETWORKS[network].Sui.rpc
); );
const build = await buildCoin( const build = await buildCoin(
provider, provider,

View File

@ -17,8 +17,9 @@ import {
PRIVATE_KEY_OPTIONS, PRIVATE_KEY_OPTIONS,
RPC_OPTIONS, RPC_OPTIONS,
} from "../../consts"; } from "../../consts";
import { Network, assertNetwork, checkBinary } from "../../utils"; import { checkBinary, getNetwork } from "../../utils";
import { YargsAddCommandsFn } from "../Yargs"; import { YargsAddCommandsFn } from "../Yargs";
import { Network } from "@wormhole-foundation/sdk";
const README_URL = const README_URL =
"https://github.com/wormhole-foundation/wormhole/blob/main/sui/README.md"; "https://github.com/wormhole-foundation/wormhole/blob/main/sui/README.md";
@ -42,8 +43,7 @@ export const addDeployCommands: YargsAddCommandsFn = (y: typeof yargs) =>
checkBinary("sui", README_URL); checkBinary("sui", README_URL);
const packageDir = argv["package-dir"]; const packageDir = argv["package-dir"];
const network = argv.network.toUpperCase(); const network = getNetwork(argv.network);
assertNetwork(network);
const debug = argv.debug ?? false; const debug = argv.debug ?? false;
const privateKey = argv["private-key"]; const privateKey = argv["private-key"];
const rpc = argv.rpc; const rpc = argv.rpc;
@ -66,7 +66,7 @@ export const deploy = async (
rpc?: string, rpc?: string,
privateKey?: string privateKey?: string
): Promise<SuiTransactionBlockResponse> => { ): Promise<SuiTransactionBlockResponse> => {
rpc = rpc ?? NETWORKS[network].sui.rpc; rpc = rpc ?? NETWORKS[network].Sui.rpc;
const provider = getProvider(network, rpc); const provider = getProvider(network, rpc);
const signer = getSigner(provider, network, privateKey); const signer = getSigner(provider, network, privateKey);

View File

@ -22,8 +22,9 @@ import {
PRIVATE_KEY_OPTIONS, PRIVATE_KEY_OPTIONS,
RPC_OPTIONS, RPC_OPTIONS,
} from "../../consts"; } from "../../consts";
import { Network, assertNetwork } from "../../utils";
import { YargsAddCommandsFn } from "../Yargs"; import { YargsAddCommandsFn } from "../Yargs";
import { getNetwork } from "../../utils";
import { Network } from "@wormhole-foundation/sdk";
export const addInitCommands: YargsAddCommandsFn = (y: typeof yargs) => export const addInitCommands: YargsAddCommandsFn = (y: typeof yargs) =>
y y
@ -48,8 +49,7 @@ export const addInitCommands: YargsAddCommandsFn = (y: typeof yargs) =>
.option("private-key", PRIVATE_KEY_OPTIONS) .option("private-key", PRIVATE_KEY_OPTIONS)
.option("rpc", RPC_OPTIONS), .option("rpc", RPC_OPTIONS),
async (argv) => { async (argv) => {
const network = argv.network.toUpperCase(); const network = getNetwork(argv.network);
assertNetwork(network);
const packageId = argv["package-id"]; const packageId = argv["package-id"];
const wormholeStateObjectId = argv["wormhole-state"]; const wormholeStateObjectId = argv["wormhole-state"];
const privateKey = argv["private-key"]; const privateKey = argv["private-key"];
@ -108,14 +108,13 @@ export const addInitCommands: YargsAddCommandsFn = (y: typeof yargs) =>
.option("private-key", PRIVATE_KEY_OPTIONS) .option("private-key", PRIVATE_KEY_OPTIONS)
.option("rpc", RPC_OPTIONS), .option("rpc", RPC_OPTIONS),
async (argv) => { async (argv) => {
const network = argv.network.toUpperCase(); const network = getNetwork(argv.network);
assertNetwork(network);
const packageId = argv["package-id"]; const packageId = argv["package-id"];
const wormholeStateObjectId = argv["wormhole-state"]; const wormholeStateObjectId = argv["wormhole-state"];
const governanceChainId = argv["governance-chain-id"]; const governanceChainId = argv["governance-chain-id"];
const governanceContract = argv["governance-address"]; const governanceContract = argv["governance-address"];
const privateKey = argv["private-key"]; const privateKey = argv["private-key"];
const rpc = argv.rpc ?? NETWORKS[network].sui.rpc; const rpc = argv.rpc ?? NETWORKS[network].Sui.rpc;
const res = await initTokenBridge( const res = await initTokenBridge(
network, network,
@ -180,8 +179,7 @@ export const addInitCommands: YargsAddCommandsFn = (y: typeof yargs) =>
.option("private-key", PRIVATE_KEY_OPTIONS) .option("private-key", PRIVATE_KEY_OPTIONS)
.option("rpc", RPC_OPTIONS), .option("rpc", RPC_OPTIONS),
async (argv) => { async (argv) => {
const network = argv.network.toUpperCase(); const network = getNetwork(argv.network);
assertNetwork(network);
const packageId = argv["package-id"]; const packageId = argv["package-id"];
const initialGuardian = argv["initial-guardian"]; const initialGuardian = argv["initial-guardian"];
const debug = argv.debug ?? false; const debug = argv.debug ?? false;
@ -222,7 +220,7 @@ export const initExampleApp = async (
rpc?: string, rpc?: string,
privateKey?: string privateKey?: string
): Promise<SuiTransactionBlockResponse> => { ): Promise<SuiTransactionBlockResponse> => {
rpc = rpc ?? NETWORKS[network].sui.rpc; rpc = rpc ?? NETWORKS[network].Sui.rpc;
const provider = getProvider(network, rpc); const provider = getProvider(network, rpc);
const signer = getSigner(provider, network, privateKey); const signer = getSigner(provider, network, privateKey);
@ -244,7 +242,7 @@ export const initTokenBridge = async (
rpc?: string, rpc?: string,
privateKey?: string privateKey?: string
): Promise<SuiTransactionBlockResponse> => { ): Promise<SuiTransactionBlockResponse> => {
rpc = rpc ?? NETWORKS[network].sui.rpc; rpc = rpc ?? NETWORKS[network].Sui.rpc;
const provider = getProvider(network, rpc); const provider = getProvider(network, rpc);
const signer = getSigner(provider, network, privateKey); const signer = getSigner(provider, network, privateKey);
const owner = await signer.getAddress(); const owner = await signer.getAddress();
@ -307,7 +305,7 @@ export const initWormhole = async (
rpc?: string, rpc?: string,
privateKey?: string privateKey?: string
): Promise<SuiTransactionBlockResponse> => { ): Promise<SuiTransactionBlockResponse> => {
rpc = rpc ?? NETWORKS[network].sui.rpc; rpc = rpc ?? NETWORKS[network].Sui.rpc;
const provider = getProvider(network, rpc); const provider = getProvider(network, rpc);
const signer = getSigner(provider, network, privateKey); const signer = getSigner(provider, network, privateKey);
const owner = await signer.getAddress(); const owner = await signer.getAddress();

View File

@ -13,8 +13,8 @@ import {
setMaxGasBudgetDevnet, setMaxGasBudgetDevnet,
} from "../../chains/sui"; } from "../../chains/sui";
import { NETWORK_OPTIONS, NETWORKS, RPC_OPTIONS } from "../../consts"; import { NETWORK_OPTIONS, NETWORKS, RPC_OPTIONS } from "../../consts";
import { assertNetwork } from "../../utils";
import { YargsAddCommandsFn } from "../Yargs"; import { YargsAddCommandsFn } from "../Yargs";
import { getNetwork } from "../../utils";
export const addPublishMessageCommands: YargsAddCommandsFn = ( export const addPublishMessageCommands: YargsAddCommandsFn = (
y: typeof yargs y: typeof yargs
@ -57,14 +57,13 @@ export const addPublishMessageCommands: YargsAddCommandsFn = (
}) })
.option("rpc", RPC_OPTIONS), .option("rpc", RPC_OPTIONS),
async (argv) => { async (argv) => {
const network = argv.network.toUpperCase(); const network = getNetwork(argv.network);
assertNetwork(network);
const packageId = argv["package-id"]; const packageId = argv["package-id"];
const stateObjectId = argv.state; const stateObjectId = argv.state;
const wormholeStateObjectId = argv["wormhole-state"]; const wormholeStateObjectId = argv["wormhole-state"];
const message = argv.message; const message = argv.message;
const privateKey = argv["private-key"]; const privateKey = argv["private-key"];
const rpc = argv.rpc ?? NETWORKS[network].sui.rpc; const rpc = argv.rpc ?? NETWORKS[network].Sui.rpc;
const provider = getProvider(network, rpc); const provider = getProvider(network, rpc);
const signer = getSigner(provider, network, privateKey); const signer = getSigner(provider, network, privateKey);

View File

@ -1,8 +1,3 @@
import {
ChainId,
ChainName,
coalesceChainName,
} from "@certusone/wormhole-sdk/lib/esm/utils/consts";
import { parseTokenBridgeRegisterChainVaa } from "@certusone/wormhole-sdk/lib/esm/vaa/tokenBridge"; import { parseTokenBridgeRegisterChainVaa } from "@certusone/wormhole-sdk/lib/esm/vaa/tokenBridge";
import { import {
JsonRpcProvider, JsonRpcProvider,
@ -36,6 +31,7 @@ import {
import { YargsAddCommandsFn } from "../Yargs"; import { YargsAddCommandsFn } from "../Yargs";
import { deploy } from "./deploy"; import { deploy } from "./deploy";
import { initExampleApp, initTokenBridge, initWormhole } from "./init"; import { initExampleApp, initTokenBridge, initWormhole } from "./init";
import { Chain, chainIdToChain, toChainId } from "@wormhole-foundation/sdk";
export const addSetupCommands: YargsAddCommandsFn = (y: typeof yargs) => export const addSetupCommands: YargsAddCommandsFn = (y: typeof yargs) =>
y.command( y.command(
@ -51,9 +47,9 @@ export const addSetupCommands: YargsAddCommandsFn = (y: typeof yargs) =>
}) })
.option("rpc", RPC_OPTIONS), .option("rpc", RPC_OPTIONS),
async (argv) => { async (argv) => {
const network = "DEVNET"; const network = "Devnet";
const privateKey = argv["private-key"]; const privateKey = argv["private-key"];
const rpc = argv.rpc ?? NETWORKS[network].sui.rpc; const rpc = argv.rpc ?? NETWORKS[network].Sui.rpc;
// Deploy core bridge // Deploy core bridge
console.log("[1/4] Deploying core bridge..."); console.log("[1/4] Deploying core bridge...");
@ -200,15 +196,15 @@ export const addSetupCommands: YargsAddCommandsFn = (y: typeof yargs) =>
dotenv.config({ path: envPath }); dotenv.config({ path: envPath });
const tx = new TransactionBlock(); const tx = new TransactionBlock();
setMaxGasBudgetDevnet("DEVNET", tx); setMaxGasBudgetDevnet("Devnet", tx);
const registrations: { chain: ChainName; module: string }[] = []; const registrations: { chain: Chain; module: string }[] = [];
for (const key in process.env) { for (const key in process.env) {
if (/^REGISTER_(.+)_TOKEN_BRIDGE_VAA$/.test(key)) { if (/^REGISTER_(.+)_TOKEN_BRIDGE_VAA$/.test(key)) {
// Get VAA info // Get VAA info
const vaa = Buffer.from(String(process.env[key]), "hex"); const vaa = Buffer.from(String(process.env[key]), "hex");
const { foreignChain, module } = const { foreignChain, module } =
parseTokenBridgeRegisterChainVaa(vaa); parseTokenBridgeRegisterChainVaa(vaa);
const chain = coalesceChainName(foreignChain as ChainId); const chain = chainIdToChain(toChainId(foreignChain));
registrations.push({ chain, module }); registrations.push({ chain, module });
// Register // Register

View File

@ -2,8 +2,8 @@ import { PaginatedObjectsResponse } from "@mysten/sui.js";
import yargs from "yargs"; import yargs from "yargs";
import { getPackageId, getProvider } from "../../chains/sui"; import { getPackageId, getProvider } from "../../chains/sui";
import { NETWORKS, NETWORK_OPTIONS, RPC_OPTIONS } from "../../consts"; import { NETWORKS, NETWORK_OPTIONS, RPC_OPTIONS } from "../../consts";
import { assertNetwork } from "../../utils";
import { YargsAddCommandsFn } from "../Yargs"; import { YargsAddCommandsFn } from "../Yargs";
import { getNetwork } from "../../utils";
export const addUtilsCommands: YargsAddCommandsFn = (y: typeof yargs) => export const addUtilsCommands: YargsAddCommandsFn = (y: typeof yargs) =>
y y
@ -20,9 +20,8 @@ export const addUtilsCommands: YargsAddCommandsFn = (y: typeof yargs) =>
.option("network", NETWORK_OPTIONS) .option("network", NETWORK_OPTIONS)
.option("rpc", RPC_OPTIONS), .option("rpc", RPC_OPTIONS),
async (argv) => { async (argv) => {
const network = argv.network.toUpperCase(); const network = getNetwork(argv.network);
assertNetwork(network); const rpc = argv.rpc ?? NETWORKS[network].Sui.rpc;
const rpc = argv.rpc ?? NETWORKS[network].sui.rpc;
const owner = argv.owner; const owner = argv.owner;
const provider = getProvider(network, rpc); const provider = getProvider(network, rpc);
@ -61,9 +60,8 @@ export const addUtilsCommands: YargsAddCommandsFn = (y: typeof yargs) =>
.option("network", NETWORK_OPTIONS) .option("network", NETWORK_OPTIONS)
.option("rpc", RPC_OPTIONS), .option("rpc", RPC_OPTIONS),
async (argv) => { async (argv) => {
const network = argv.network.toUpperCase(); const network = getNetwork(argv.network);
assertNetwork(network); const rpc = argv.rpc ?? NETWORKS[network].Sui.rpc;
const rpc = argv.rpc ?? NETWORKS[network].sui.rpc;
const provider = getProvider(network, rpc); const provider = getProvider(network, rpc);
console.log(await getPackageId(provider, argv["state-object-id"])); console.log(await getPackageId(provider, argv["state-object-id"]));
} }
@ -89,9 +87,8 @@ export const addUtilsCommands: YargsAddCommandsFn = (y: typeof yargs) =>
} as const) } as const)
.option("rpc", RPC_OPTIONS), .option("rpc", RPC_OPTIONS),
async (argv) => { async (argv) => {
const network = argv.network.toUpperCase(); const network = getNetwork(argv.network);
assertNetwork(network); const rpc = argv.rpc ?? NETWORKS[network].Sui.rpc;
const rpc = argv.rpc ?? NETWORKS[network].sui.rpc;
const provider = getProvider(network, rpc); const provider = getProvider(network, rpc);
console.log( console.log(
JSON.stringify( JSON.stringify(

View File

@ -1,13 +1,6 @@
import {
isCosmWasmChain,
isEVMChain,
isTerraChain,
} from "@certusone/wormhole-sdk/lib/esm/utils/consts";
import yargs from "yargs"; import yargs from "yargs";
import { impossible } from "../vaa";
import { transferEVM } from "../evm"; import { transferEVM } from "../evm";
import { CHAIN_NAME_CHOICES, NETWORK_OPTIONS, NETWORKS } from "../consts"; import { CHAIN_NAME_CHOICES, NETWORK_OPTIONS, NETWORKS } from "../consts";
import { assertNetwork } from "../utils";
import { transferTerra } from "../terra"; import { transferTerra } from "../terra";
import { transferInjective } from "../injective"; import { transferInjective } from "../injective";
import { transferXpla } from "../xpla"; import { transferXpla } from "../xpla";
@ -16,6 +9,13 @@ import { transferAlgorand } from "../algorand";
import { transferNear } from "../near"; import { transferNear } from "../near";
import { transferSui } from "../chains/sui/transfer"; import { transferSui } from "../chains/sui/transfer";
import { transferAptos } from "../aptos"; import { transferAptos } from "../aptos";
import {
Chain,
PlatformToChains,
chainToPlatform,
toChain,
} from "@wormhole-foundation/sdk-base";
import { chainToChain, getNetwork } from "../utils";
export const command = "transfer"; export const command = "transfer";
export const desc = "Transfer a token"; export const desc = "Transfer a token";
@ -23,12 +23,12 @@ export const builder = (y: typeof yargs) =>
y y
.option("src-chain", { .option("src-chain", {
describe: "source chain", describe: "source chain",
choices: CHAIN_NAME_CHOICES, type: "string",
demandOption: true, demandOption: true,
}) })
.option("dst-chain", { .option("dst-chain", {
describe: "destination chain", describe: "destination chain",
choices: CHAIN_NAME_CHOICES, type: "string",
demandOption: true, demandOption: true,
}) })
.option("dst-addr", { .option("dst-addr", {
@ -58,16 +58,10 @@ export const builder = (y: typeof yargs) =>
export const handler = async ( export const handler = async (
argv: Awaited<ReturnType<typeof builder>["argv"]> argv: Awaited<ReturnType<typeof builder>["argv"]>
) => { ) => {
const srcChain = argv["src-chain"]; const srcChain: Chain = chainToChain(argv["src-chain"]);
const dstChain = argv["dst-chain"]; const dstChain: Chain = chainToChain(argv["dst-chain"]);
if (srcChain === "unset") {
throw new Error("source chain is unset");
}
if (dstChain === "unset") {
throw new Error("destination chain is unset");
}
// TODO: support transfers to sei // TODO: support transfers to sei
if (dstChain === "sei") { if (dstChain === "Sei") {
throw new Error("transfer to sei currently unsupported"); throw new Error("transfer to sei currently unsupported");
} }
if (srcChain === dstChain) { if (srcChain === dstChain) {
@ -78,19 +72,18 @@ export const handler = async (
throw new Error("amount must be greater than 0"); throw new Error("amount must be greater than 0");
} }
const tokenAddr = argv["token-addr"]; const tokenAddr = argv["token-addr"];
if (tokenAddr === "native" && isCosmWasmChain(srcChain)) { if (tokenAddr === "native" && chainToPlatform(srcChain) === "Cosmwasm") {
throw new Error(`token-addr must be specified for ${srcChain}`); throw new Error(`token-addr must be specified for ${srcChain}`);
} }
const dstAddr = argv["dst-addr"]; const dstAddr = argv["dst-addr"];
const network = argv.network.toUpperCase(); const network = getNetwork(argv.network);
assertNetwork(network); const rpc = argv.rpc ?? NETWORKS[network][toChain(srcChain)].rpc;
const rpc = argv.rpc ?? NETWORKS[network][srcChain].rpc;
if (!rpc) { if (!rpc) {
throw new Error(`No ${network} rpc defined for ${srcChain}`); throw new Error(`No ${network} rpc defined for ${srcChain}`);
} }
if (isEVMChain(srcChain)) { if (chainToPlatform(srcChain) === "Evm") {
await transferEVM( await transferEVM(
srcChain, srcChain as PlatformToChains<"Evm">,
dstChain, dstChain,
dstAddr, dstAddr,
tokenAddr, tokenAddr,
@ -98,7 +91,7 @@ export const handler = async (
network, network,
rpc rpc
); );
} else if (isTerraChain(srcChain)) { } else if (srcChain === "Terra" || srcChain === "Terra2") {
await transferTerra( await transferTerra(
srcChain, srcChain,
dstChain, dstChain,
@ -108,7 +101,7 @@ export const handler = async (
network, network,
rpc rpc
); );
} else if (srcChain === "solana" || srcChain === "pythnet") { } else if (srcChain === "Solana" || srcChain === "Pythnet") {
await transferSolana( await transferSolana(
srcChain, srcChain,
dstChain, dstChain,
@ -118,49 +111,37 @@ export const handler = async (
network, network,
rpc rpc
); );
} else if (srcChain === "algorand") { } else if (srcChain === "Algorand") {
await transferAlgorand(dstChain, dstAddr, tokenAddr, amount, network, rpc); await transferAlgorand(dstChain, dstAddr, tokenAddr, amount, network, rpc);
} else if (srcChain === "near") { } else if (srcChain === "Near") {
await transferNear(dstChain, dstAddr, tokenAddr, amount, network, rpc); await transferNear(dstChain, dstAddr, tokenAddr, amount, network, rpc);
} else if (srcChain === "injective") { } else if (srcChain === "Injective") {
await transferInjective(dstChain, dstAddr, tokenAddr, amount, network, rpc); await transferInjective(dstChain, dstAddr, tokenAddr, amount, network, rpc);
} else if (srcChain === "xpla") { } else if (srcChain === "Xpla") {
await transferXpla(dstChain, dstAddr, tokenAddr, amount, network, rpc); await transferXpla(dstChain, dstAddr, tokenAddr, amount, network, rpc);
} else if (srcChain === "sei") { } else if (srcChain === "Sei") {
throw new Error("sei is not supported yet"); throw new Error("sei is not supported yet");
} else if (srcChain === "osmosis") { } else if (srcChain === "Osmosis") {
throw Error("OSMOSIS is not supported yet"); throw Error("OSMOSIS is not supported yet");
} else if (srcChain === "sui") { } else if (srcChain === "Sui") {
await transferSui(dstChain, dstAddr, tokenAddr, amount, network, rpc); await transferSui(dstChain, dstAddr, tokenAddr, amount, network, rpc);
} else if (srcChain === "aptos") { } else if (srcChain === "Aptos") {
await transferAptos(dstChain, dstAddr, tokenAddr, amount, network, rpc); await transferAptos(dstChain, dstAddr, tokenAddr, amount, network, rpc);
} else if (srcChain === "wormchain") { } else if (srcChain === "Wormchain") {
throw Error("Wormchain is not supported yet"); throw Error("Wormchain is not supported yet");
} else if (srcChain === "btc") { } else if (srcChain === "Btc") {
throw Error("btc is not supported yet"); throw Error("btc is not supported yet");
} else if (srcChain === "cosmoshub") { } else if (srcChain === "Cosmoshub") {
throw Error("cosmoshub is not supported yet"); throw Error("cosmoshub is not supported yet");
} else if (srcChain === "evmos") { } else if (srcChain === "Evmos") {
throw Error("evmos is not supported yet"); throw Error("evmos is not supported yet");
} else if (srcChain === "kujira") { } else if (srcChain === "Kujira") {
throw Error("kujira is not supported yet"); throw Error("kujira is not supported yet");
} else if (srcChain === "neutron") { } else if (srcChain === "Neutron") {
throw Error("neutron is not supported yet"); throw Error("neutron is not supported yet");
} else if (srcChain === "celestia") { } else if (srcChain === "Celestia") {
throw Error("celestia is not supported yet"); throw Error("celestia is not supported yet");
} else if (srcChain === "stargaze") {
throw Error("stargaze is not supported yet");
} else if (srcChain === "seda") {
throw Error("seda is not supported yet");
} else if (srcChain === "dymension") {
throw Error("dymension is not supported yet");
} else if (srcChain === "provenance") {
throw Error("provenance is not supported yet");
} else if (srcChain === "rootstock") {
throw Error("rootstock is not supported yet");
} else { } else {
// If you get a type error here, hover over `chain`'s type and it tells you throw new Error(`${srcChain} is not supported yet`);
// which cases are not handled
impossible(srcChain);
} }
}; };

View File

@ -1,11 +1,11 @@
// The verify-vaa command invokes the parseAndVerifyVM method on the core contract on Ethereum to verify the specified VAA. // The verify-vaa command invokes the parseAndVerifyVM method on the core contract on Ethereum to verify the specified VAA.
import { Implementation__factory } from "@certusone/wormhole-sdk/lib/esm/ethers-contracts"; import { Implementation__factory } from "@certusone/wormhole-sdk/lib/esm/ethers-contracts";
import { CONTRACTS } from "@certusone/wormhole-sdk/lib/esm/utils/consts";
import { ethers } from "ethers"; import { ethers } from "ethers";
import yargs from "yargs"; import yargs from "yargs";
import { NETWORKS, NETWORK_OPTIONS } from "../consts"; import { NETWORKS, NETWORK_OPTIONS } from "../consts";
import { assertNetwork } from "../utils"; import { getNetwork } from "../utils";
import { contracts } from "@wormhole-foundation/sdk";
export const command = "verify-vaa"; export const command = "verify-vaa";
export const desc = "Verifies a VAA by querying the core contract on Ethereum"; export const desc = "Verifies a VAA by querying the core contract on Ethereum";
@ -21,17 +21,16 @@ export const builder = (y: typeof yargs) =>
export const handler = async ( export const handler = async (
argv: Awaited<ReturnType<typeof builder>["argv"]> argv: Awaited<ReturnType<typeof builder>["argv"]>
) => { ) => {
const network = argv.network.toUpperCase(); const network = getNetwork(argv.network);
assertNetwork(network);
const buf = Buffer.from(String(argv.vaa), "hex"); const buf = Buffer.from(String(argv.vaa), "hex");
const contract_address = CONTRACTS[network].ethereum.core; const contract_address = contracts.coreBridge(network, "Ethereum");
if (!contract_address) { if (!contract_address) {
throw Error(`Unknown core contract on ${network} for ethereum`); throw Error(`Unknown core contract on ${network} for ethereum`);
} }
const provider = new ethers.providers.JsonRpcProvider( const provider = new ethers.providers.JsonRpcProvider(
NETWORKS[network].ethereum.rpc NETWORKS[network].Ethereum.rpc
); );
const contract = Implementation__factory.connect(contract_address, provider); const contract = Implementation__factory.connect(contract_address, provider);
const result = await contract.parseAndVerifyVM(buf); const result = await contract.parseAndVerifyVM(buf);

View File

@ -1,60 +1,6 @@
import { import { chainToChainId } from "@wormhole-foundation/sdk-base";
CHAIN_ID_SOLANA,
CONTRACTS as SDK_CONTRACTS,
} from "@certusone/wormhole-sdk/lib/esm/utils/consts";
const OVERRIDES = { export const GOVERNANCE_CHAIN = chainToChainId("Solana");
MAINNET: {
sui: {
core: "0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c",
token_bridge:
"0xc57508ee0d4595e5a8728974a4a93a787d38f339757230d441e895422c07aba9",
},
aptos: {
token_bridge:
"0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f",
core: "0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625",
nft_bridge:
"0x1bdffae984043833ed7fe223f7af7a3f8902d04129b14f801823e64827da7130",
},
},
TESTNET: {
sui: {
core: "0x31358d198147da50db32eda2562951d53973a0c0ad5ed738e9b17d88b213d790",
token_bridge:
"0x6fb10cdb7aa299e9a4308752dadecb049ff55a892de92992a1edbd7912b3d6da",
},
aptos: {
token_bridge:
"0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f",
core: "0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625",
nft_bridge: undefined,
},
},
DEVNET: {
sui: {
core: "0x12253210c90f89e7a8525e6c52d41309ff5bfb31f43f561b5fe6f50cd72f9668", // wormhole module State object ID
token_bridge:
"0x830ed228c6f1bcb40003bb49af3277df2cbf933d63a6bcdcb0ba4580a1a7654e", // token_bridge module State object ID
},
aptos: {
token_bridge:
"0x84a5f374d29fc77e370014dce4fd6a55b58ad608de8074b0be5571701724da31",
core: "0xde0036a9600559e295d5f6802ef6f3f802f510366e0c23912b0655d972166017",
nft_bridge:
"0x46da3d4c569388af61f951bdd1153f4c875f90c2991f6b2d0a38e2161a40852c",
},
},
};
// TODO(aki): move this to SDK at some point
export const CONTRACTS = {
MAINNET: { ...SDK_CONTRACTS.MAINNET, ...OVERRIDES.MAINNET },
TESTNET: { ...SDK_CONTRACTS.TESTNET, ...OVERRIDES.TESTNET },
DEVNET: { ...SDK_CONTRACTS.DEVNET, ...OVERRIDES.DEVNET },
};
export const GOVERNANCE_CHAIN = CHAIN_ID_SOLANA;
export const GOVERNANCE_EMITTER = export const GOVERNANCE_EMITTER =
"0000000000000000000000000000000000000000000000000000000000000004"; "0000000000000000000000000000000000000000000000000000000000000004";
export const INITIAL_GUARDIAN_DEVNET = export const INITIAL_GUARDIAN_DEVNET =

View File

@ -1,4 +1,4 @@
import { ChainName } from "@certusone/wormhole-sdk/lib/esm/utils/consts"; import { Chain } from "@wormhole-foundation/sdk-base";
import { config } from "dotenv"; import { config } from "dotenv";
import { homedir } from "os"; import { homedir } from "os";
@ -12,785 +12,773 @@ export type Connection = {
}; };
export type ChainConnections = { export type ChainConnections = {
[chain in ChainName]: Connection; [chain in Chain]: Connection;
}; };
const MAINNET = { const Mainnet = {
unset: { Solana: {
rpc: undefined,
key: undefined,
},
solana: {
rpc: "https://api.mainnet-beta.solana.com", rpc: "https://api.mainnet-beta.solana.com",
key: getEnvVar("SOLANA_KEY"), key: getEnvVar("SOLANA_KEY"),
}, },
terra: { Terra: {
rpc: "https://lcd.terra.dev", rpc: "https://lcd.terra.dev",
chain_id: "columbus-5", chain_id: "columbus-5",
key: getEnvVar("TERRA_MNEMONIC"), key: getEnvVar("TERRA_MNEMONIC"),
}, },
ethereum: { Ethereum: {
rpc: `https://rpc.ankr.com/eth`, rpc: `https://rpc.ankr.com/eth`,
key: getEnvVar("ETH_KEY"), key: getEnvVar("ETH_KEY"),
chain_id: 1, chain_id: 1,
}, },
bsc: { Bsc: {
rpc: "https://bsc-dataseed.binance.org/", rpc: "https://bsc-dataseed.binance.org/",
key: getEnvVar("ETH_KEY"), key: getEnvVar("ETH_KEY"),
chain_id: 56, chain_id: 56,
}, },
polygon: { Polygon: {
rpc: "https://rpc.ankr.com/polygon", rpc: "https://rpc.ankr.com/polygon",
key: getEnvVar("ETH_KEY"), key: getEnvVar("ETH_KEY"),
chain_id: 137, chain_id: 137,
}, },
avalanche: { Avalanche: {
rpc: "https://rpc.ankr.com/avalanche", rpc: "https://rpc.ankr.com/avalanche",
key: getEnvVar("ETH_KEY"), key: getEnvVar("ETH_KEY"),
chain_id: 43114, chain_id: 43114,
}, },
algorand: { Algorand: {
rpc: "https://mainnet-api.algonode.cloud", rpc: "https://mainnet-api.algonode.cloud",
key: getEnvVar("ALGORAND_KEY"), key: getEnvVar("ALGORAND_KEY"),
}, },
oasis: { Oasis: {
rpc: "https://emerald.oasis.dev/", rpc: "https://emerald.oasis.dev/",
key: getEnvVar("ETH_KEY"), key: getEnvVar("ETH_KEY"),
chain_id: 42262, chain_id: 42262,
}, },
fantom: { Fantom: {
rpc: "https://rpc.ftm.tools/", rpc: "https://rpc.ftm.tools/",
key: getEnvVar("ETH_KEY"), key: getEnvVar("ETH_KEY"),
chain_id: 250, chain_id: 250,
}, },
aurora: { Aurora: {
rpc: "https://mainnet.aurora.dev", rpc: "https://mainnet.aurora.dev",
key: getEnvVar("ETH_KEY"), key: getEnvVar("ETH_KEY"),
chain_id: 1313161554, chain_id: 1313161554,
}, },
karura: { Karura: {
rpc: "https://eth-rpc-karura.aca-api.network/", rpc: "https://eth-rpc-karura.aca-api.network/",
key: getEnvVar("ETH_KEY"), key: getEnvVar("ETH_KEY"),
chain_id: 686, chain_id: 686,
}, },
acala: { Acala: {
rpc: "https://eth-rpc-acala.aca-api.network/", rpc: "https://eth-rpc-acala.aca-api.network/",
key: getEnvVar("ETH_KEY"), key: getEnvVar("ETH_KEY"),
chain_id: 787, chain_id: 787,
}, },
klaytn: { Klaytn: {
rpc: "https://public-node-api.klaytnapi.com/v1/cypress", rpc: "https://public-node-api.klaytnapi.com/v1/cypress",
key: getEnvVar("ETH_KEY"), key: getEnvVar("ETH_KEY"),
chain_id: 8217, chain_id: 8217,
}, },
celo: { Celo: {
rpc: "https://forno.celo.org", rpc: "https://forno.celo.org",
key: getEnvVar("ETH_KEY"), key: getEnvVar("ETH_KEY"),
chain_id: 42220, chain_id: 42220,
}, },
near: { Near: {
rpc: "https://rpc.mainnet.near.org", rpc: "https://rpc.mainnet.near.org",
key: getEnvVar("NEAR_KEY"), key: getEnvVar("NEAR_KEY"),
networkId: "mainnet", networkId: "mainnet",
}, },
injective: { Injective: {
rpc: "http://sentry0.injective.network:26657", rpc: "http://sentry0.injective.network:26657",
chain_id: "injective-1", chain_id: "injective-1",
key: getEnvVar("INJECTIVE_KEY"), key: getEnvVar("INJECTIVE_KEY"),
}, },
osmosis: { Osmosis: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
}, },
aptos: { Aptos: {
rpc: "https://fullnode.mainnet.aptoslabs.com/v1", rpc: "https://fullnode.mainnet.aptoslabs.com/v1",
key: getEnvVar("APTOS_KEY"), key: getEnvVar("APTOS_KEY"),
}, },
sui: { Sui: {
rpc: "https://fullnode.mainnet.sui.io:443", rpc: "https://fullnode.mainnet.sui.io:443",
key: getEnvVar("SUI_KEY"), key: getEnvVar("SUI_KEY"),
}, },
pythnet: { Pythnet: {
rpc: "http://api.pythnet.pyth.network:8899/", rpc: "http://api.pythnet.pyth.network:8899/",
key: getEnvVar("SOLANA_KEY"), key: getEnvVar("SOLANA_KEY"),
}, },
xpla: { Xpla: {
rpc: "https://dimension-lcd.xpla.dev", rpc: "https://dimension-lcd.xpla.dev",
chain_id: "dimension_37-1", chain_id: "dimension_37-1",
key: getEnvVar("XPLA_KEY"), key: getEnvVar("XPLA_KEY"),
}, },
btc: { Btc: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
}, },
wormchain: { Wormchain: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
}, },
moonbeam: { Moonbeam: {
rpc: "https://rpc.api.moonbeam.network", rpc: "https://rpc.api.moonbeam.network",
key: getEnvVar("ETH_KEY"), key: getEnvVar("ETH_KEY"),
chain_id: 1284, chain_id: 1284,
}, },
neon: { Neon: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
terra2: { Terra2: {
rpc: "https://phoenix-lcd.terra.dev", rpc: "https://phoenix-lcd.terra.dev",
chain_id: "phoenix-1", chain_id: "phoenix-1",
key: getEnvVar("TERRA_MNEMONIC"), key: getEnvVar("TERRA_MNEMONIC"),
}, },
arbitrum: { Arbitrum: {
rpc: "https://arb1.arbitrum.io/rpc", rpc: "https://arb1.arbitrum.io/rpc",
key: getEnvVar("ETH_KEY"), key: getEnvVar("ETH_KEY"),
chain_id: 42161, chain_id: 42161,
}, },
optimism: { Optimism: {
rpc: "https://mainnet.optimism.io", rpc: "https://mainnet.optimism.io",
key: getEnvVar("ETH_KEY"), key: getEnvVar("ETH_KEY"),
chain_id: 10, chain_id: 10,
}, },
gnosis: { Gnosis: {
rpc: "https://rpc.gnosischain.com/", rpc: "https://rpc.gnosischain.com/",
key: getEnvVar("ETH_KEY"), key: getEnvVar("ETH_KEY"),
chain_id: 100, chain_id: 100,
}, },
base: { Base: {
rpc: "https://mainnet.base.org", rpc: "https://mainnet.base.org",
key: getEnvVar("ETH_KEY"), key: getEnvVar("ETH_KEY"),
chain_id: 8453, chain_id: 8453,
}, },
sei: { Sei: {
rpc: "https://sei-rpc.polkachu.com/", rpc: "https://sei-rpc.polkachu.com/",
key: getEnvVar("SEI_KEY"), key: getEnvVar("SEI_KEY"),
}, },
rootstock: { Rootstock: {
rpc: "https://public-node.rsk.co", rpc: "https://public-node.rsk.co",
key: getEnvVar("ETH_KEY"), key: getEnvVar("ETH_KEY"),
chain_id: 30, chain_id: 30,
}, },
scroll: { Scroll: {
rpc: "https://rpc.ankr.com/scroll", rpc: "https://rpc.ankr.com/scroll",
key: getEnvVar("ETH_KEY"), key: getEnvVar("ETH_KEY"),
chain_id: 534352, chain_id: 534352,
}, },
mantle: { Mantle: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
blast: { Blast: {
rpc: "https://rpc.ankr.com/blast", rpc: "https://rpc.ankr.com/blast",
key: getEnvVar("ETH_KEY"), key: getEnvVar("ETH_KEY"),
chain_id: 81457, chain_id: 81457,
}, },
xlayer: { Xlayer: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
linea: { Linea: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
berachain: { Berachain: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
seievm: { Seievm: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
sepolia: { Sepolia: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
holesky: { Holesky: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
cosmoshub: { Cosmoshub: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
evmos: { Evmos: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
kujira: { Kujira: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
neutron: { Neutron: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
celestia: { Celestia: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
arbitrum_sepolia: { ArbitrumSepolia: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
base_sepolia: { BaseSepolia: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
optimism_sepolia: { OptimismSepolia: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
polygon_sepolia: { PolygonSepolia: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
stargaze: { Stargaze: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
seda: { Seda: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
dymension: { Dymension: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
provenance: { Provenance: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
}; };
const TESTNET = { const Testnet = {
unset: { Solana: {
rpc: undefined,
key: undefined,
},
solana: {
rpc: "https://api.devnet.solana.com", rpc: "https://api.devnet.solana.com",
key: getEnvVar("SOLANA_KEY_TESTNET"), key: getEnvVar("SOLANA_KEY_TESTNET"),
}, },
terra: { Terra: {
rpc: "https://bombay-lcd.terra.dev", rpc: "https://bombay-lcd.terra.dev",
chain_id: "bombay-12", chain_id: "bombay-12",
key: getEnvVar("TERRA_MNEMONIC_TESTNET"), key: getEnvVar("TERRA_MNEMONIC_TESTNET"),
}, },
ethereum: { Ethereum: {
rpc: `https://rpc.ankr.com/eth_goerli`, rpc: `https://rpc.ankr.com/eth_goerli`,
key: getEnvVar("ETH_KEY_TESTNET"), key: getEnvVar("ETH_KEY_TESTNET"),
chain_id: 5, chain_id: 5,
}, },
bsc: { Bsc: {
rpc: "https://data-seed-prebsc-1-s1.binance.org:8545", rpc: "https://data-seed-prebsc-1-s1.binance.org:8545",
key: getEnvVar("ETH_KEY_TESTNET"), key: getEnvVar("ETH_KEY_TESTNET"),
chain_id: 97, chain_id: 97,
}, },
polygon: { Polygon: {
rpc: `https://rpc.ankr.com/polygon_mumbai`, rpc: `https://rpc.ankr.com/polygon_mumbai`,
key: getEnvVar("ETH_KEY_TESTNET"), key: getEnvVar("ETH_KEY_TESTNET"),
chain_id: 80001, chain_id: 80001,
}, },
avalanche: { Avalanche: {
rpc: "https://rpc.ankr.com/avalanche_fuji", rpc: "https://rpc.ankr.com/avalanche_fuji",
key: getEnvVar("ETH_KEY_TESTNET"), key: getEnvVar("ETH_KEY_TESTNET"),
chain_id: 43113, chain_id: 43113,
}, },
oasis: { Oasis: {
rpc: "https://testnet.emerald.oasis.dev", rpc: "https://testnet.emerald.oasis.dev",
key: getEnvVar("ETH_KEY_TESTNET"), key: getEnvVar("ETH_KEY_TESTNET"),
chain_id: 42261, chain_id: 42261,
}, },
algorand: { Algorand: {
rpc: "https://testnet-api.algonode.cloud", rpc: "https://testnet-api.algonode.cloud",
key: getEnvVar("ALGORAND_KEY_TESTNET"), key: getEnvVar("ALGORAND_KEY_TESTNET"),
}, },
fantom: { Fantom: {
rpc: "https://rpc.testnet.fantom.network", rpc: "https://rpc.testnet.fantom.network",
key: getEnvVar("ETH_KEY_TESTNET"), key: getEnvVar("ETH_KEY_TESTNET"),
chain_id: 4002, chain_id: 4002,
}, },
aurora: { Aurora: {
rpc: "https://testnet.aurora.dev", rpc: "https://testnet.aurora.dev",
key: getEnvVar("ETH_KEY_TESTNET"), key: getEnvVar("ETH_KEY_TESTNET"),
chain_id: 1313161555, chain_id: 1313161555,
}, },
karura: { Karura: {
rpc: "https://eth-rpc-karura-testnet.aca-staging.network", rpc: "https://eth-rpc-karura-testnet.aca-staging.network",
key: getEnvVar("ETH_KEY_TESTNET"), key: getEnvVar("ETH_KEY_TESTNET"),
chain_id: 596, chain_id: 596,
}, },
acala: { Acala: {
rpc: "https://eth-rpc-acala-testnet.aca-staging.network", rpc: "https://eth-rpc-acala-testnet.aca-staging.network",
key: getEnvVar("ETH_KEY_TESTNET"), key: getEnvVar("ETH_KEY_TESTNET"),
chain_id: 595, chain_id: 595,
}, },
klaytn: { Klaytn: {
rpc: "https://api.baobab.klaytn.net:8651", rpc: "https://api.baobab.klaytn.net:8651",
key: getEnvVar("ETH_KEY_TESTNET"), key: getEnvVar("ETH_KEY_TESTNET"),
chain_id: 1001, chain_id: 1001,
}, },
celo: { Celo: {
rpc: "https://alfajores-forno.celo-testnet.org", rpc: "https://alfajores-forno.celo-testnet.org",
key: getEnvVar("ETH_KEY_TESTNET"), key: getEnvVar("ETH_KEY_TESTNET"),
chain_id: 44787, chain_id: 44787,
}, },
near: { Near: {
rpc: "https://rpc.testnet.near.org", rpc: "https://rpc.testnet.near.org",
key: getEnvVar("NEAR_KEY_TESTNET"), key: getEnvVar("NEAR_KEY_TESTNET"),
networkId: "testnet", networkId: "testnet",
}, },
injective: { Injective: {
rpc: "https://k8s.testnet.tm.injective.network:443", rpc: "https://k8s.testnet.tm.injective.network:443",
chain_id: "injective-888", chain_id: "injective-888",
key: getEnvVar("INJECTIVE_KEY_TESTNET"), key: getEnvVar("INJECTIVE_KEY_TESTNET"),
}, },
osmosis: { Osmosis: {
rpc: undefined, rpc: undefined,
chain_id: "osmo-test-4", chain_id: "osmo-test-4",
key: getEnvVar("OSMOSIS_KEY_TESTNET"), key: getEnvVar("OSMOSIS_KEY_TESTNET"),
}, },
aptos: { Aptos: {
rpc: "https://fullnode.testnet.aptoslabs.com/v1", rpc: "https://fullnode.testnet.aptoslabs.com/v1",
key: getEnvVar("APTOS_TESTNET"), key: getEnvVar("APTOS_TESTNET"),
}, },
sui: { Sui: {
rpc: "https://fullnode.testnet.sui.io:443", rpc: "https://fullnode.testnet.sui.io:443",
key: getEnvVar("SUI_KEY_TESTNET"), key: getEnvVar("SUI_KEY_TESTNET"),
}, },
pythnet: { Pythnet: {
rpc: "https://api.pythtest.pyth.network/", rpc: "https://api.pythtest.pyth.network/",
key: getEnvVar("SOLANA_KEY_TESTNET"), key: getEnvVar("SOLANA_KEY_TESTNET"),
}, },
xpla: { Xpla: {
rpc: "https://cube-lcd.xpla.dev:443", rpc: "https://cube-lcd.xpla.dev:443",
chain_id: "cube_47-5", chain_id: "cube_47-5",
key: getEnvVar("XPLA_KEY_TESTNET"), key: getEnvVar("XPLA_KEY_TESTNET"),
}, },
sei: { Sei: {
rpc: "https://rpc.atlantic-2.seinetwork.io", rpc: "https://rpc.atlantic-2.seinetwork.io",
key: getEnvVar("SEI_KEY_TESTNET"), key: getEnvVar("SEI_KEY_TESTNET"),
}, },
scroll: { Scroll: {
rpc: "https://rpc.ankr.com/scroll_sepolia_testnet", rpc: "https://rpc.ankr.com/scroll_sepolia_testnet",
key: getEnvVar("ETH_KEY_TESTNET"), key: getEnvVar("ETH_KEY_TESTNET"),
chain_id: 534353, chain_id: 534353,
}, },
mantle: { Mantle: {
rpc: "https://mantle-sepolia.drpc.org", rpc: "https://mantle-sepolia.drpc.org",
key: getEnvVar("ETH_KEY_TESTNET"), key: getEnvVar("ETH_KEY_TESTNET"),
chain_id: 5003, chain_id: 5003,
}, },
blast: { Blast: {
rpc: "https://blast-sepolia.drpc.org", rpc: "https://blast-sepolia.drpc.org",
key: getEnvVar("ETH_KEY_TESTNET"), key: getEnvVar("ETH_KEY_TESTNET"),
chain_id: 168587773, chain_id: 168587773,
}, },
xlayer: { Xlayer: {
rpc: "https://testrpc.xlayer.tech/", rpc: "https://testrpc.xlayer.tech/",
key: getEnvVar("ETH_KEY_TESTNET"), key: getEnvVar("ETH_KEY_TESTNET"),
chain_id: 195, chain_id: 195,
}, },
linea: { Linea: {
rpc: "https://rpc.sepolia.linea.build", rpc: "https://rpc.sepolia.linea.build",
key: getEnvVar("ETH_KEY_TESTNET"), key: getEnvVar("ETH_KEY_TESTNET"),
chain_id: 59141, chain_id: 59141,
}, },
berachain: { Berachain: {
rpc: "https://artio.rpc.berachain.com/", rpc: "https://artio.rpc.berachain.com/",
key: getEnvVar("ETH_KEY_TESTNET"), key: getEnvVar("ETH_KEY_TESTNET"),
chain_id: 80085, chain_id: 80085,
}, },
seievm: { Seievm: {
rpc: "https://evm-rpc-arctic-1.sei-apis.com/", rpc: "https://evm-rpc-arctic-1.sei-apis.com/",
key: getEnvVar("ETH_KEY_TESTNET"), key: getEnvVar("ETH_KEY_TESTNET"),
chain_id: 713715, chain_id: 713715,
}, },
sepolia: { Sepolia: {
rpc: "https://rpc.ankr.com/eth_sepolia", rpc: "https://rpc.ankr.com/eth_sepolia",
key: getEnvVar("ETH_KEY_TESTNET"), key: getEnvVar("ETH_KEY_TESTNET"),
chain_id: 11155111, chain_id: 11155111,
}, },
holesky: { Holesky: {
rpc: "https://rpc.ankr.com/eth_holesky", rpc: "https://rpc.ankr.com/eth_holesky",
key: getEnvVar("ETH_KEY_TESTNET"), key: getEnvVar("ETH_KEY_TESTNET"),
chain_id: 17000, chain_id: 17000,
}, },
btc: { Btc: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
}, },
wormchain: { Wormchain: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
}, },
moonbeam: { Moonbeam: {
rpc: "https://rpc.api.moonbase.moonbeam.network", rpc: "https://rpc.api.moonbase.moonbeam.network",
key: getEnvVar("ETH_KEY_TESTNET"), key: getEnvVar("ETH_KEY_TESTNET"),
chain_id: 1287, chain_id: 1287,
}, },
neon: { Neon: {
rpc: "https://proxy.devnet.neonlabs.org/solana", rpc: "https://proxy.devnet.neonlabs.org/solana",
key: getEnvVar("ETH_KEY_TESTNET"), key: getEnvVar("ETH_KEY_TESTNET"),
chain_id: undefined, chain_id: undefined,
}, },
terra2: { Terra2: {
rpc: "https://pisco-lcd.terra.dev", rpc: "https://pisco-lcd.terra.dev",
chain_id: "pisco-1", chain_id: "pisco-1",
key: getEnvVar("TERRA_MNEMONIC_TESTNET"), key: getEnvVar("TERRA_MNEMONIC_TESTNET"),
}, },
arbitrum: { Arbitrum: {
rpc: "https://goerli-rollup.arbitrum.io/rpc", rpc: "https://goerli-rollup.arbitrum.io/rpc",
key: getEnvVar("ETH_KEY_TESTNET"), key: getEnvVar("ETH_KEY_TESTNET"),
chain_id: 421613, chain_id: 421613,
}, },
optimism: { Optimism: {
rpc: "https://goerli.optimism.io", rpc: "https://goerli.optimism.io",
key: getEnvVar("ETH_KEY_TESTNET"), key: getEnvVar("ETH_KEY_TESTNET"),
chain_id: 420, chain_id: 420,
}, },
gnosis: { Gnosis: {
rpc: "https://sokol.poa.network/", rpc: "https://sokol.poa.network/",
key: getEnvVar("ETH_KEY_TESTNET"), key: getEnvVar("ETH_KEY_TESTNET"),
chain_id: 77, chain_id: 77,
}, },
base: { Base: {
rpc: "https://goerli.base.org", rpc: "https://goerli.base.org",
key: getEnvVar("ETH_KEY_TESTNET"), key: getEnvVar("ETH_KEY_TESTNET"),
chain_id: 84531, chain_id: 84531,
}, },
rootstock: { Rootstock: {
rpc: "https://public-node.testnet.rsk.co", rpc: "https://public-node.testnet.rsk.co",
key: getEnvVar("ETH_KEY_TESTNET"), key: getEnvVar("ETH_KEY_TESTNET"),
chain_id: 31, chain_id: 31,
}, },
cosmoshub: { Cosmoshub: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
evmos: { Evmos: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
kujira: { Kujira: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
neutron: { Neutron: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
celestia: { Celestia: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
arbitrum_sepolia: { ArbitrumSepolia: {
rpc: "https://arbitrum-sepolia.publicnode.com", rpc: "https://arbitrum-sepolia.publicnode.com",
key: getEnvVar("ETH_KEY_TESTNET"), key: getEnvVar("ETH_KEY_TESTNET"),
chain_id: 421614, chain_id: 421614,
}, },
base_sepolia: { BaseSepolia: {
rpc: "https://sepolia.base.org", rpc: "https://sepolia.base.org",
key: getEnvVar("ETH_KEY_TESTNET"), key: getEnvVar("ETH_KEY_TESTNET"),
chain_id: 84532, chain_id: 84532,
}, },
optimism_sepolia: { OptimismSepolia: {
rpc: "https://rpc.ankr.com/optimism_sepolia", rpc: "https://rpc.ankr.com/optimism_sepolia",
key: getEnvVar("ETH_KEY_TESTNET"), key: getEnvVar("ETH_KEY_TESTNET"),
chain_id: 11155420, chain_id: 11155420,
}, },
polygon_sepolia: { PolygonSepolia: {
rpc: "https://rpc-amoy.polygon.technology/", rpc: "https://rpc-amoy.polygon.technology/",
key: getEnvVar("ETH_KEY_TESTNET"), key: getEnvVar("ETH_KEY_TESTNET"),
chain_id: 80002, chain_id: 80002,
}, },
stargaze: { Stargaze: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
seda: { Seda: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
dymension: { Dymension: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
provenance: { Provenance: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
}; };
const DEVNET = { const Devnet = {
unset: { Solana: {
rpc: undefined,
key: undefined,
},
solana: {
rpc: "http://localhost:8899", rpc: "http://localhost:8899",
key: "J2D4pwDred8P9ioyPEZVLPht885AeYpifsFGUyuzVmiKQosAvmZP4EegaKFrSprBC5vVP1xTvu61vYDWsxBNsYx", key: "J2D4pwDred8P9ioyPEZVLPht885AeYpifsFGUyuzVmiKQosAvmZP4EegaKFrSprBC5vVP1xTvu61vYDWsxBNsYx",
}, },
terra: { Terra: {
rpc: "http://localhost:1317", rpc: "http://localhost:1317",
chain_id: "columbus-5", chain_id: "columbus-5",
key: "notice oak worry limit wrap speak medal online prefer cluster roof addict wrist behave treat actual wasp year salad speed social layer crew genius", key: "notice oak worry limit wrap speak medal online prefer cluster roof addict wrist behave treat actual wasp year salad speed social layer crew genius",
}, },
ethereum: { Ethereum: {
rpc: "http://localhost:8545", rpc: "http://localhost:8545",
key: "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d", key: "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d",
}, },
bsc: { Bsc: {
rpc: "http://localhost:8546", rpc: "http://localhost:8546",
key: "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d", key: "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d",
}, },
polygon: { Polygon: {
rpc: undefined, rpc: undefined,
key: "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d", key: "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d",
}, },
avalanche: { Avalanche: {
rpc: undefined, rpc: undefined,
key: "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d", key: "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d",
}, },
oasis: { Oasis: {
rpc: undefined, rpc: undefined,
key: "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d", key: "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d",
}, },
algorand: { Algorand: {
rpc: "http://localhost", rpc: "http://localhost",
key: getEnvVar("ALGORAND_KEY_DEVNET"), key: getEnvVar("ALGORAND_KEY_DEVNET"),
}, },
fantom: { Fantom: {
rpc: undefined, rpc: undefined,
key: "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d", key: "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d",
}, },
aurora: { Aurora: {
rpc: undefined, rpc: undefined,
key: "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d", key: "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d",
}, },
karura: { Karura: {
rpc: undefined, rpc: undefined,
key: "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d", key: "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d",
}, },
acala: { Acala: {
rpc: undefined, rpc: undefined,
key: "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d", key: "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d",
}, },
klaytn: { Klaytn: {
rpc: undefined, rpc: undefined,
key: "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d", key: "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d",
}, },
celo: { Celo: {
rpc: undefined, rpc: undefined,
key: "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d", key: "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d",
}, },
near: { Near: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
networkId: "sandbox", networkId: "sandbox",
}, },
injective: { Injective: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
}, },
osmosis: { Osmosis: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
}, },
pythnet: { Pythnet: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
}, },
btc: { Btc: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
}, },
xpla: { Xpla: {
rpc: undefined, rpc: undefined,
chain_id: undefined, chain_id: undefined,
key: undefined, key: undefined,
}, },
sei: { Sei: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
}, },
scroll: { Scroll: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
mantle: { Mantle: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
blast: { Blast: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
xlayer: { Xlayer: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
linea: { Linea: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
berachain: { Berachain: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
seievm: { Seievm: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
sepolia: { Sepolia: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
}, },
holesky: { Holesky: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
}, },
wormchain: { Wormchain: {
rpc: "http://localhost:1319", rpc: "http://localhost:1319",
chain_id: "wormchain", chain_id: "wormchain",
key: undefined, key: undefined,
}, },
aptos: { Aptos: {
rpc: "http://0.0.0.0:8080", rpc: "http://0.0.0.0:8080",
key: "537c1f91e56891445b491068f519b705f8c0f1a1e66111816dd5d4aa85b8113d", key: "537c1f91e56891445b491068f519b705f8c0f1a1e66111816dd5d4aa85b8113d",
}, },
sui: { Sui: {
rpc: "http://0.0.0.0:9000", rpc: "http://0.0.0.0:9000",
key: "AGA20wtGcwbcNAG4nwapbQ5wIuXwkYQEWFUoSVAxctHb", key: "AGA20wtGcwbcNAG4nwapbQ5wIuXwkYQEWFUoSVAxctHb",
}, },
moonbeam: { Moonbeam: {
rpc: undefined, rpc: undefined,
key: "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d", key: "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d",
}, },
neon: { Neon: {
rpc: undefined, rpc: undefined,
key: "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d", key: "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d",
}, },
terra2: { Terra2: {
rpc: "http://localhost:1318", rpc: "http://localhost:1318",
chain_id: "phoenix-1", chain_id: "phoenix-1",
key: "notice oak worry limit wrap speak medal online prefer cluster roof addict wrist behave treat actual wasp year salad speed social layer crew genius", key: "notice oak worry limit wrap speak medal online prefer cluster roof addict wrist behave treat actual wasp year salad speed social layer crew genius",
}, },
arbitrum: { Arbitrum: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
}, },
optimism: { Optimism: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
}, },
gnosis: { Gnosis: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
}, },
base: { Base: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
}, },
rootstock: { Rootstock: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
}, },
cosmoshub: { Cosmoshub: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
}, },
evmos: { Evmos: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
}, },
kujira: { Kujira: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
}, },
neutron: { Neutron: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
celestia: { Celestia: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
arbitrum_sepolia: { ArbitrumSepolia: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
base_sepolia: { BaseSepolia: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
optimism_sepolia: { OptimismSepolia: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
polygon_sepolia: { PolygonSepolia: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
stargaze: { Stargaze: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
seda: { Seda: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
dymension: { Dymension: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
}, },
provenance: { Provenance: {
rpc: undefined, rpc: undefined,
key: undefined, key: undefined,
chain_id: undefined, chain_id: undefined,
@ -811,18 +799,18 @@ const DEVNET = {
* *
* (Do not delete this declaration!) * (Do not delete this declaration!)
*/ */
const isTestnetConnections: ChainConnections = TESTNET; const isTestnetConnections: ChainConnections = Testnet;
/** /**
* *
* See [[isTestnetContracts]] * See [[isTestnetContracts]]
*/ */
const isMainnetConnections: ChainConnections = MAINNET; const isMainnetConnections: ChainConnections = Mainnet;
/** /**
* *
* See [[isTestnetContracts]] * See [[isTestnetContracts]]
*/ */
const isDevnetConnections: ChainConnections = DEVNET; const isDevnetConnections: ChainConnections = Devnet;
export const NETWORKS = { MAINNET, TESTNET, DEVNET }; export const NETWORKS = { Mainnet, Testnet, Devnet };

View File

@ -1,8 +1,9 @@
import { import {
CHAINS, Chain,
ChainId, ChainId,
ChainName, chainIds,
} from "@certusone/wormhole-sdk/lib/esm/utils/consts"; chains,
} from "@wormhole-foundation/sdk-base";
export const DEBUG_OPTIONS = { export const DEBUG_OPTIONS = {
alias: "d", alias: "d",
@ -38,11 +39,9 @@ export const RPC_OPTIONS = {
demandOption: false, demandOption: false,
} as const; } as const;
export const CHAIN_ID_OR_NAME_CHOICES = [ export const CHAIN_ID_OR_NAME_CHOICES = [...chains, ...chainIds] as (
...Object.keys(CHAINS), | Chain
...Object.values(CHAINS), | ChainId
] as (ChainName | ChainId)[]; )[];
export const CHAIN_NAME_CHOICES = Object.keys(CHAINS).filter( export const CHAIN_NAME_CHOICES = [...chains];
(c) => c !== "unset"
) as ChainName[];

View File

@ -1,9 +1,3 @@
import {
ChainId,
ChainName,
isCosmWasmChain,
} from "@certusone/wormhole-sdk/lib/esm/utils/consts";
import { import {
getEmitterAddressAlgorand, getEmitterAddressAlgorand,
getEmitterAddressEth, getEmitterAddressEth,
@ -11,21 +5,25 @@ import {
getEmitterAddressSolana, getEmitterAddressSolana,
getEmitterAddressTerra, getEmitterAddressTerra,
} from "@certusone/wormhole-sdk/lib/esm/bridge/getEmitterAddress"; } from "@certusone/wormhole-sdk/lib/esm/bridge/getEmitterAddress";
import {
Chain,
ChainId,
chainToPlatform,
toChain,
} from "@wormhole-foundation/sdk-base";
export async function getEmitterAddress( export async function getEmitterAddress(chain: ChainId | Chain, addr: string) {
chain: ChainId | ChainName, const localChain = toChain(chain);
addr: string if (localChain === "Solana" || localChain === "Pythnet") {
) {
if (chain === "solana" || chain === "pythnet") {
// TODO: Create an isSolanaChain() // TODO: Create an isSolanaChain()
addr = getEmitterAddressSolana(addr); addr = getEmitterAddressSolana(addr);
} else if (isCosmWasmChain(chain)) { } else if (chainToPlatform(localChain) === "Cosmwasm") {
addr = await getEmitterAddressTerra(addr); addr = await getEmitterAddressTerra(addr);
} else if (chain === "algorand") { } else if (localChain === "Algorand") {
addr = getEmitterAddressAlgorand(BigInt(addr)); addr = getEmitterAddressAlgorand(BigInt(addr));
} else if (chain === "near") { } else if (localChain === "Near") {
addr = getEmitterAddressNear(addr); addr = getEmitterAddressNear(addr);
} else if (chain === "aptos") { } else if (localChain === "Aptos") {
// TODO: There should be something in the SDK to do this. // TODO: There should be something in the SDK to do this.
if ( if (
addr === addr ===
@ -42,7 +40,7 @@ export async function getEmitterAddress(
} else { } else {
throw Error(`Unsupported Aptos address: ${addr}`); throw Error(`Unsupported Aptos address: ${addr}`);
} }
} else if (chain === "sui") { } else if (localChain === "Sui") {
// TODO: There should be something in the SDK to do this. // TODO: There should be something in the SDK to do this.
if ( if (
addr === addr ===

View File

@ -5,20 +5,10 @@ import {
NFTBridgeImplementation__factory, NFTBridgeImplementation__factory,
} from "@certusone/wormhole-sdk/lib/esm/ethers-contracts"; } from "@certusone/wormhole-sdk/lib/esm/ethers-contracts";
import { WormholeRelayer__factory } from "@certusone/wormhole-sdk/lib/esm/ethers-relayer-contracts"; import { WormholeRelayer__factory } from "@certusone/wormhole-sdk/lib/esm/ethers-relayer-contracts";
import { getWormholeRelayerAddress } from "@certusone/wormhole-sdk/lib/esm/relayer";
import {
CHAINS,
CONTRACTS,
ChainName,
Contracts,
EVMChainName,
toChainId,
} from "@certusone/wormhole-sdk/lib/esm/utils/consts";
import axios from "axios"; import axios from "axios";
import { ethers } from "ethers"; import { ethers } from "ethers";
import { solidityKeccak256 } from "ethers/lib/utils"; import { solidityKeccak256 } from "ethers/lib/utils";
import { NETWORKS } from "./consts"; import { NETWORKS } from "./consts";
import { Network } from "./utils";
import { Encoding, Payload, encode, impossible, typeWidth } from "./vaa"; import { Encoding, Payload, encode, impossible, typeWidth } from "./vaa";
import { import {
approveEth, approveEth,
@ -26,14 +16,22 @@ import {
transferFromEth, transferFromEth,
transferFromEthNative, transferFromEthNative,
} from "@certusone/wormhole-sdk/lib/esm/token_bridge/transfer"; } from "@certusone/wormhole-sdk/lib/esm/token_bridge/transfer";
import { tryNativeToUint8Array } from "@certusone/wormhole-sdk/lib/esm/utils"; import {
Chain,
Network,
PlatformToChains,
chainToChainId,
chains,
contracts,
} from "@wormhole-foundation/sdk-base";
import { tryNativeToUint8Array } from "./sdk/array";
const _IMPLEMENTATION_SLOT = const _IMPLEMENTATION_SLOT =
"0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc"; "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc";
export async function query_contract_evm( export async function query_contract_evm(
network: Network, network: Network,
chain: EVMChainName, chain: PlatformToChains<"Evm">,
module: "Core" | "NFTBridge" | "TokenBridge", module: "Core" | "NFTBridge" | "TokenBridge",
contract_address: string | undefined, contract_address: string | undefined,
_rpc: string | undefined _rpc: string | undefined
@ -44,12 +42,13 @@ export async function query_contract_evm(
throw Error(`No ${network} rpc defined for ${chain} (see networks.ts)`); throw Error(`No ${network} rpc defined for ${chain} (see networks.ts)`);
} }
const contracts: Contracts = CONTRACTS[network][chain];
const provider = new ethers.providers.JsonRpcProvider(rpc); const provider = new ethers.providers.JsonRpcProvider(rpc);
const result: any = {}; const result: any = {};
switch (module) { switch (module) {
case "Core": case "Core":
contract_address = contract_address ? contract_address : contracts.core; contract_address = contract_address
? contract_address
: contracts.coreBridge.get(network, chain);
if (!contract_address) { if (!contract_address) {
throw Error(`Unknown core contract on ${network} for ${chain}`); throw Error(`Unknown core contract on ${network} for ${chain}`);
} }
@ -105,7 +104,7 @@ export async function query_contract_evm(
case "TokenBridge": case "TokenBridge":
contract_address = contract_address contract_address = contract_address
? contract_address ? contract_address
: contracts.token_bridge; : contracts.tokenBridge.get(network, chain);
if (contract_address === undefined) { if (contract_address === undefined) {
throw Error(`Unknown token bridge contract on ${network} for ${chain}`); throw Error(`Unknown token bridge contract on ${network} for ${chain}`);
} }
@ -115,11 +114,11 @@ export async function query_contract_evm(
); );
result.address = contract_address; result.address = contract_address;
const registrationsPromise = Promise.all( const registrationsPromise = Promise.all(
Object.entries(CHAINS) chains
.filter(([c_name, _]) => c_name !== chain && c_name !== "unset") .filter((c_name) => c_name !== chain)
.map(async ([c_name, c_id]) => [ .map(async (c_name) => [
c_name, c_name,
await tb.bridgeContracts(c_id), await tb.bridgeContracts(chainToChainId(c_name)),
]) ])
); );
const [ const [
@ -167,7 +166,7 @@ export async function query_contract_evm(
case "NFTBridge": case "NFTBridge":
contract_address = contract_address contract_address = contract_address
? contract_address ? contract_address
: contracts.nft_bridge; : contracts.nftBridge.get(network, chain);
if (contract_address === undefined) { if (contract_address === undefined) {
throw Error(`Unknown nft bridge contract on ${network} for ${chain}`); throw Error(`Unknown nft bridge contract on ${network} for ${chain}`);
} }
@ -177,11 +176,11 @@ export async function query_contract_evm(
); );
result.address = contract_address; result.address = contract_address;
const registrationsPromiseNb = Promise.all( const registrationsPromiseNb = Promise.all(
Object.entries(CHAINS) chains
.filter(([c_name, _]) => c_name !== chain && c_name !== "unset") .filter(([c_name, _]) => c_name !== chain)
.map(async ([c_name, c_id]) => [ .map(async (c_name) => [
c_name, c_name,
await nb.bridgeContracts(c_id), await nb.bridgeContracts(chainToChainId(c_name)),
]) ])
); );
const [ const [
@ -232,7 +231,7 @@ export async function query_contract_evm(
export async function getImplementation( export async function getImplementation(
network: Network, network: Network,
chain: EVMChainName, chain: PlatformToChains<"Evm">,
module: "Core" | "NFTBridge" | "TokenBridge", module: "Core" | "NFTBridge" | "TokenBridge",
contract_address: string | undefined, contract_address: string | undefined,
_rpc: string | undefined _rpc: string | undefined
@ -243,20 +242,21 @@ export async function getImplementation(
throw Error(`No ${network} rpc defined for ${chain} (see networks.ts)`); throw Error(`No ${network} rpc defined for ${chain} (see networks.ts)`);
} }
const contracts: Contracts = CONTRACTS[network][chain];
switch (module) { switch (module) {
case "Core": case "Core":
contract_address = contract_address ? contract_address : contracts.core; contract_address = contract_address
? contract_address
: contracts.coreBridge.get(network, chain);
break; break;
case "TokenBridge": case "TokenBridge":
contract_address = contract_address contract_address = contract_address
? contract_address ? contract_address
: contracts.token_bridge; : contracts.tokenBridge.get(network, chain);
break; break;
case "NFTBridge": case "NFTBridge":
contract_address = contract_address contract_address = contract_address
? contract_address ? contract_address
: contracts.nft_bridge; : contracts.nftBridge.get(network, chain);
break; break;
default: default:
impossible(module); impossible(module);
@ -271,10 +271,14 @@ export async function getImplementation(
)[0]; )[0];
} }
async function getSigner(chain: EVMChainName, key: string, rpc: string) { async function getSigner(
chain: PlatformToChains<"Evm">,
key: string,
rpc: string
) {
let provider: ethers.providers.JsonRpcProvider; let provider: ethers.providers.JsonRpcProvider;
let signer: ethers.Wallet; let signer: ethers.Wallet;
if (chain === "celo") { if (chain === "Celo") {
provider = new celo.CeloProvider(rpc); provider = new celo.CeloProvider(rpc);
await provider.ready; await provider.ready;
signer = new celo.CeloWallet(key, provider); signer = new celo.CeloWallet(key, provider);
@ -286,15 +290,15 @@ async function getSigner(chain: EVMChainName, key: string, rpc: string) {
// NOTE: some of these might have only been tested on mainnet. If it fails in // NOTE: some of these might have only been tested on mainnet. If it fails in
// testnet (or devnet), they might require additional guards // testnet (or devnet), they might require additional guards
let overrides: ethers.Overrides = {}; let overrides: ethers.Overrides = {};
if (chain === "karura" || chain == "acala") { if (chain === "Karura" || chain == "Acala") {
overrides = await getKaruraGasParams(rpc); overrides = await getKaruraGasParams(rpc);
} else if (chain === "polygon") { } else if (chain === "Polygon") {
const feeData = await provider.getFeeData(); const feeData = await provider.getFeeData();
overrides = { overrides = {
maxFeePerGas: feeData.maxFeePerGas?.mul(50) || undefined, maxFeePerGas: feeData.maxFeePerGas?.mul(50) || undefined,
maxPriorityFeePerGas: feeData.maxPriorityFeePerGas?.mul(50) || undefined, maxPriorityFeePerGas: feeData.maxPriorityFeePerGas?.mul(50) || undefined,
}; };
} else if (chain === "klaytn" || chain === "fantom") { } else if (chain === "Klaytn" || chain === "Fantom") {
overrides = { gasPrice: (await signer.getGasPrice()).toString() }; overrides = { gasPrice: (await signer.getGasPrice()).toString() };
} }
return { return {
@ -308,7 +312,7 @@ export async function execute_evm(
payload: Payload, payload: Payload,
vaa: Buffer, vaa: Buffer,
network: Network, network: Network,
chain: EVMChainName, chain: PlatformToChains<"Evm">,
contract_address: string | undefined, contract_address: string | undefined,
_rpc: string | undefined _rpc: string | undefined
) { ) {
@ -323,12 +327,14 @@ export async function execute_evm(
} }
const key: string = n.key; const key: string = n.key;
const contracts: Contracts = CONTRACTS[network][chain]; // const contracts: Contracts = CONTRACTS[network][chain];
const { signer, overrides } = await getSigner(chain, key, rpc); const { signer, overrides } = await getSigner(chain, key, rpc);
switch (payload.module) { switch (payload.module) {
case "Core": { case "Core": {
contract_address = contract_address ? contract_address : contracts.core; contract_address = contract_address
? contract_address
: contracts.coreBridge.get(network, chain);
if (contract_address === undefined) { if (contract_address === undefined) {
throw Error(`Unknown core contract on ${network} for ${chain}`); throw Error(`Unknown core contract on ${network} for ${chain}`);
} }
@ -362,7 +368,7 @@ export async function execute_evm(
case "NFTBridge": { case "NFTBridge": {
contract_address = contract_address contract_address = contract_address
? contract_address ? contract_address
: contracts.nft_bridge; : contracts.nftBridge.get(network, chain);
if (contract_address === undefined) { if (contract_address === undefined) {
throw Error(`Unknown nft bridge contract on ${network} for ${chain}`); throw Error(`Unknown nft bridge contract on ${network} for ${chain}`);
} }
@ -401,7 +407,7 @@ export async function execute_evm(
case "TokenBridge": { case "TokenBridge": {
contract_address = contract_address contract_address = contract_address
? contract_address ? contract_address
: contracts.token_bridge; : contracts.tokenBridge.get(network, chain);
if (contract_address === undefined) { if (contract_address === undefined) {
throw Error(`Unknown token bridge contract on ${network} for ${chain}`); throw Error(`Unknown token bridge contract on ${network} for ${chain}`);
} }
@ -451,7 +457,7 @@ export async function execute_evm(
case "WormholeRelayer": case "WormholeRelayer":
contract_address = contract_address contract_address = contract_address
? contract_address ? contract_address
: getWormholeRelayerAddress(chain, network); : contracts.relayer.get(network, chain);
if (contract_address === undefined) { if (contract_address === undefined) {
throw Error( throw Error(
`Unknown Wormhole Relayer contract on ${network} for ${chain}` `Unknown Wormhole Relayer contract on ${network} for ${chain}`
@ -493,8 +499,8 @@ export async function execute_evm(
} }
export async function transferEVM( export async function transferEVM(
srcChain: EVMChainName, srcChain: PlatformToChains<"Evm">,
dstChain: ChainName, dstChain: Chain,
dstAddress: string, dstAddress: string,
tokenAddress: string, tokenAddress: string,
amount: string, amount: string,
@ -505,7 +511,7 @@ export async function transferEVM(
if (!n.key) { if (!n.key) {
throw Error(`No ${network} key defined for ${srcChain} (see networks.ts)`); throw Error(`No ${network} key defined for ${srcChain} (see networks.ts)`);
} }
const { token_bridge } = CONTRACTS[network][srcChain]; const token_bridge = contracts.tokenBridge.get(network, srcChain);
if (!token_bridge) { if (!token_bridge) {
throw Error(`Unknown token bridge contract on ${network} for ${srcChain}`); throw Error(`Unknown token bridge contract on ${network} for ${srcChain}`);
} }
@ -516,8 +522,8 @@ export async function transferEVM(
token_bridge, token_bridge,
signer, signer,
amount, amount,
toChainId(dstChain), chainToChainId(dstChain),
tryNativeToUint8Array(dstAddress, dstChain) tryNativeToUint8Array(dstAddress, chainToChainId(dstChain))
); );
} else { } else {
const allowance = await getAllowanceEth(token_bridge, tokenAddress, signer); const allowance = await getAllowanceEth(token_bridge, tokenAddress, signer);
@ -529,8 +535,8 @@ export async function transferEVM(
signer, signer,
tokenAddress, tokenAddress,
amount, amount,
dstChain, chainToChainId(dstChain),
tryNativeToUint8Array(dstAddress, dstChain), tryNativeToUint8Array(dstAddress, chainToChainId(dstChain)),
undefined, undefined,
overrides overrides
); );
@ -828,11 +834,10 @@ const isUnsupportedError = (e: any): e is { reason: string } =>
export async function queryRegistrationsEvm( export async function queryRegistrationsEvm(
network: Network, network: Network,
chain: EVMChainName, chain: PlatformToChains<"Evm">,
module: "Core" | "NFTBridge" | "TokenBridge" module: "Core" | "NFTBridge" | "TokenBridge"
): Promise<Object> { ): Promise<Object> {
const n = NETWORKS[network][chain]; const n = NETWORKS[network][chain];
const contracts = CONTRACTS[network][chain];
let targetContract: string | undefined; let targetContract: string | undefined;
let contract: any; let contract: any;
@ -841,7 +846,7 @@ export async function queryRegistrationsEvm(
switch (module) { switch (module) {
case "TokenBridge": case "TokenBridge":
targetContract = contracts.token_bridge; targetContract = contracts.tokenBridge.get(network, chain);
if (targetContract === undefined) { if (targetContract === undefined) {
throw Error(`Unknown token bridge contract on ${network} for ${chain}`); throw Error(`Unknown token bridge contract on ${network} for ${chain}`);
} }
@ -851,7 +856,7 @@ export async function queryRegistrationsEvm(
); );
break; break;
case "NFTBridge": case "NFTBridge":
targetContract = contracts.nft_bridge; targetContract = contracts.nftBridge.get(network, chain);
if (targetContract === undefined) { if (targetContract === undefined) {
throw Error(`Unknown NFT bridge contract on ${network} for ${chain}`); throw Error(`Unknown NFT bridge contract on ${network} for ${chain}`);
} }
@ -865,9 +870,12 @@ export async function queryRegistrationsEvm(
} }
const registrations: string[][] = await Promise.all( const registrations: string[][] = await Promise.all(
Object.entries(CHAINS) chains
.filter(([cname, _]) => cname !== chain && cname !== "unset") .filter((cname) => cname !== chain)
.map(async ([cname, cid]) => [cname, await contract.bridgeContracts(cid)]) .map(async (cname) => [
cname,
await contract.bridgeContracts(chainToChainId(cname)),
])
); );
const results: { [key: string]: string } = {}; const results: { [key: string]: string } = {};

View File

@ -1,8 +1,3 @@
import {
CHAINS,
CONTRACTS,
ChainName,
} from "@certusone/wormhole-sdk/lib/esm/utils/consts";
import { import {
getNetworkInfo, getNetworkInfo,
Network as InjectiveNetwork, Network as InjectiveNetwork,
@ -19,28 +14,33 @@ import {
import { DEFAULT_STD_FEE, getStdFee } from "@injectivelabs/utils"; import { DEFAULT_STD_FEE, getStdFee } from "@injectivelabs/utils";
import { fromUint8Array } from "js-base64"; import { fromUint8Array } from "js-base64";
import { NETWORKS } from "./consts"; import { NETWORKS } from "./consts";
import { Network } from "./utils";
import { impossible, Payload } from "./vaa"; import { impossible, Payload } from "./vaa";
import { transferFromInjective } from "@certusone/wormhole-sdk/lib/esm/token_bridge/injective"; import { transferFromInjective } from "@certusone/wormhole-sdk/lib/esm/token_bridge/injective";
import { tryNativeToUint8Array } from "@certusone/wormhole-sdk/lib/esm/utils"; import {
Chain,
chainToChainId,
contracts,
Network,
} from "@wormhole-foundation/sdk-base";
import { chains } from "@wormhole-foundation/sdk";
import { tryNativeToUint8Array } from "./sdk/array";
export async function execute_injective( export async function execute_injective(
payload: Payload, payload: Payload,
vaa: Buffer, vaa: Buffer,
network: Network network: Network
) { ) {
if (network === "DEVNET") { if (network === "Devnet") {
throw new Error("Injective is not supported in DEVNET"); throw new Error("Injective is not supported in DEVNET");
} }
const chain = "injective"; const chain = "Injective";
let { key } = NETWORKS[network][chain]; let { key } = NETWORKS[network][chain];
if (!key) { if (!key) {
throw Error(`No ${network} key defined for Injective`); throw Error(`No ${network} key defined for Injective`);
} }
let contracts = CONTRACTS[network][chain];
const endPoint = const endPoint =
network === "MAINNET" network === "Mainnet"
? InjectiveNetwork.MainnetK8s ? InjectiveNetwork.MainnetK8s
: InjectiveNetwork.TestnetK8s; : InjectiveNetwork.TestnetK8s;
@ -55,7 +55,7 @@ export async function execute_injective(
switch (payload.module) { switch (payload.module) {
case "Core": { case "Core": {
target_contract = contracts.core; target_contract = contracts.coreBridge(network, "Injective");
action = "submit_v_a_a"; action = "submit_v_a_a";
execute_msg = { execute_msg = {
vaa: fromUint8Array(vaa), vaa: fromUint8Array(vaa),
@ -76,14 +76,15 @@ export async function execute_injective(
break; break;
} }
case "NFTBridge": { case "NFTBridge": {
if (!contracts.nft_bridge) { const nftContract = contracts.nftBridge.get(network, "Injective");
if (!nftContract) {
// NOTE: this code can safely be removed once the injective NFT bridge is // NOTE: this code can safely be removed once the injective NFT bridge is
// released, but it's fine for it to stay, as the condition will just be // released, but it's fine for it to stay, as the condition will just be
// skipped once 'contracts.nft_bridge' is defined // skipped once 'contracts.nft_bridge' is defined
throw new Error("NFT bridge not supported yet for injective"); throw new Error("NFT bridge not supported yet for injective");
} }
target_contract = contracts.nft_bridge; target_contract = nftContract;
action = "submit_vaa"; action = "submit_vaa";
execute_msg = { execute_msg = {
data: fromUint8Array(vaa), data: fromUint8Array(vaa),
@ -107,12 +108,12 @@ export async function execute_injective(
break; break;
} }
case "TokenBridge": { case "TokenBridge": {
console.log("contracts:", contracts); const tbContract = contracts.tokenBridge.get(network, "Injective");
if (!contracts.token_bridge) { if (!tbContract) {
throw new Error("contracts.token_bridge is undefined"); throw new Error("contracts.token_bridge is undefined");
} }
target_contract = contracts.token_bridge; target_contract = tbContract;
action = "submit_vaa"; action = "submit_vaa";
execute_msg = { execute_msg = {
data: fromUint8Array(vaa), data: fromUint8Array(vaa),
@ -165,22 +166,22 @@ export async function execute_injective(
} }
export async function transferInjective( export async function transferInjective(
dstChain: ChainName, dstChain: Chain,
dstAddress: string, dstAddress: string,
tokenAddress: string, tokenAddress: string,
amount: string, amount: string,
network: Network, network: Network,
rpc: string rpc: string
) { ) {
if (network === "DEVNET") { if (network === "Devnet") {
throw new Error("Injective is not supported in DEVNET"); throw new Error("Injective is not supported in DEVNET");
} }
const chain = "injective"; const chain = "Injective";
const { key } = NETWORKS[network][chain]; const { key } = NETWORKS[network][chain];
if (!key) { if (!key) {
throw Error(`No ${network} key defined for Injective`); throw Error(`No ${network} key defined for Injective`);
} }
const { token_bridge } = CONTRACTS[network][chain]; const token_bridge = contracts.tokenBridge.get(network, "Injective");
if (token_bridge == undefined) { if (token_bridge == undefined) {
throw Error(`Unknown token bridge contract on ${network} for ${chain}`); throw Error(`Unknown token bridge contract on ${network} for ${chain}`);
} }
@ -193,8 +194,8 @@ export async function transferInjective(
token_bridge, token_bridge,
tokenAddress, tokenAddress,
amount, amount,
dstChain, chainToChainId(dstChain),
tryNativeToUint8Array(dstAddress, dstChain) tryNativeToUint8Array(dstAddress, chainToChainId(dstChain))
); );
await signAndSendTx(walletPK, network, msgs); await signAndSendTx(walletPK, network, msgs);
@ -268,18 +269,17 @@ export async function queryRegistrationsInjective(
network: Network, network: Network,
module: "Core" | "NFTBridge" | "TokenBridge" module: "Core" | "NFTBridge" | "TokenBridge"
) { ) {
const chain = "injective"; const chain = "Injective";
const n = NETWORKS[network][chain]; const n = NETWORKS[network][chain];
const contracts = CONTRACTS[network][chain];
let targetContract: string | undefined; let targetContract: string | undefined;
switch (module) { switch (module) {
case "TokenBridge": case "TokenBridge":
targetContract = contracts.token_bridge; targetContract = contracts.tokenBridge.get(network, "Injective");
break; break;
case "NFTBridge": case "NFTBridge":
targetContract = contracts.nft_bridge; targetContract = contracts.nftBridge.get(network, "Injective");
break; break;
default: default:
throw new Error(`Invalid module: ${module}`); throw new Error(`Invalid module: ${module}`);
@ -297,14 +297,14 @@ export async function queryRegistrationsInjective(
// Query the bridge registration for all the chains in parallel. // Query the bridge registration for all the chains in parallel.
const registrations: (any | null)[][] = await Promise.all( const registrations: (any | null)[][] = await Promise.all(
Object.entries(CHAINS) chains
.filter(([cname, _]) => cname !== chain && cname !== "unset") .filter((cname) => cname !== chain)
.map(async ([cname, cid]) => [ .map(async (cname) => [
cname, cname,
await (async () => { await (async () => {
let query_msg = { let query_msg = {
chain_registration: { chain_registration: {
chain: cid, chain: chainToChainId(cname),
}, },
}; };

View File

@ -1,18 +1,19 @@
import {
ChainName,
CONTRACTS,
} from "@certusone/wormhole-sdk/lib/esm/utils/consts";
import BN from "bn.js"; import BN from "bn.js";
import { Account, connect, KeyPair } from "near-api-js"; import { Account, connect, KeyPair } from "near-api-js";
import { InMemoryKeyStore } from "near-api-js/lib/key_stores"; import { InMemoryKeyStore } from "near-api-js/lib/key_stores";
import { NETWORKS } from "./consts"; import { NETWORKS } from "./consts";
import { Network } from "./utils";
import { impossible, Payload } from "./vaa"; import { impossible, Payload } from "./vaa";
import { import {
transferNearFromNear, transferNearFromNear,
transferTokenFromNear, transferTokenFromNear,
} from "@certusone/wormhole-sdk/lib/esm/token_bridge/transfer"; } from "@certusone/wormhole-sdk/lib/esm/token_bridge/transfer";
import { tryNativeToUint8Array } from "@certusone/wormhole-sdk/lib/esm/utils"; import {
Chain,
chainToChainId,
contracts,
Network,
} from "@wormhole-foundation/sdk-base";
import { tryNativeToUint8Array } from "./sdk/array";
export function keyPairToImplicitAccount(keyPair: KeyPair): string { export function keyPairToImplicitAccount(keyPair: KeyPair): string {
return Buffer.from(keyPair.getPublicKey().data).toString("hex"); return Buffer.from(keyPair.getPublicKey().data).toString("hex");
@ -23,7 +24,7 @@ export const execute_near = async (
vaa: string, vaa: string,
network: Network network: Network
): Promise<void> => { ): Promise<void> => {
const { rpc, key, networkId } = NETWORKS[network].near; const { rpc, key, networkId } = NETWORKS[network].Near;
if (!key) { if (!key) {
throw Error(`No ${network} key defined for NEAR`); throw Error(`No ${network} key defined for NEAR`);
} }
@ -32,16 +33,15 @@ export const execute_near = async (
throw Error(`No ${network} rpc defined for NEAR`); throw Error(`No ${network} rpc defined for NEAR`);
} }
const contracts = CONTRACTS[network].near;
let target_contract: string; let target_contract: string;
let numSubmits = 1; let numSubmits = 1;
switch (payload.module) { switch (payload.module) {
case "Core": { case "Core": {
if (!contracts.core) { const coreContract = contracts.coreBridge(network, "Near");
if (!coreContract) {
throw new Error(`Core bridge address not defined for NEAR ${network}`); throw new Error(`Core bridge address not defined for NEAR ${network}`);
} }
target_contract = coreContract;
target_contract = contracts.core;
switch (payload.type) { switch (payload.type) {
case "GuardianSetUpgrade": case "GuardianSetUpgrade":
console.log("Submitting new guardian set"); console.log("Submitting new guardian set");
@ -57,12 +57,13 @@ export const execute_near = async (
break; break;
} }
case "NFTBridge": { case "NFTBridge": {
if (!contracts.nft_bridge) { const nftContract = contracts.nftBridge.get(network, "Near");
if (!nftContract) {
throw new Error(`NFT bridge address not defined for NEAR ${network}`); throw new Error(`NFT bridge address not defined for NEAR ${network}`);
} }
numSubmits = 2; numSubmits = 2;
target_contract = contracts.nft_bridge; target_contract = nftContract;
switch (payload.type) { switch (payload.type) {
case "ContractUpgrade": case "ContractUpgrade":
console.log("Upgrading contract"); console.log("Upgrading contract");
@ -82,12 +83,13 @@ export const execute_near = async (
break; break;
} }
case "TokenBridge": { case "TokenBridge": {
if (!contracts.token_bridge) { const tbContract = contracts.tokenBridge(network, "Near");
if (!tbContract) {
throw new Error(`Token bridge address not defined for NEAR ${network}`); throw new Error(`Token bridge address not defined for NEAR ${network}`);
} }
numSubmits = 2; numSubmits = 2;
target_contract = contracts.token_bridge; target_contract = tbContract;
switch (payload.type) { switch (payload.type) {
case "ContractUpgrade": case "ContractUpgrade":
console.log("Upgrading contract"); console.log("Upgrading contract");
@ -158,18 +160,19 @@ export const execute_near = async (
}; };
export async function transferNear( export async function transferNear(
dstChain: ChainName, dstChain: Chain,
dstAddress: string, dstAddress: string,
tokenAddress: string, tokenAddress: string,
amount: string, amount: string,
network: Network, network: Network,
rpc: string rpc: string
) { ) {
const { key, networkId } = NETWORKS[network].near; const { key, networkId } = NETWORKS[network].Near;
if (!key) { if (!key) {
throw Error(`No ${network} key defined for NEAR`); throw Error(`No ${network} key defined for NEAR`);
} }
const { core, token_bridge } = CONTRACTS[network].near; const core = contracts.coreBridge(network, "Near");
const token_bridge = contracts.tokenBridge(network, "Near");
if (core === undefined) { if (core === undefined) {
throw Error(`Unknown core contract on ${network} for NEAR`); throw Error(`Unknown core contract on ${network} for NEAR`);
} }
@ -193,8 +196,8 @@ export async function transferNear(
core, core,
token_bridge, token_bridge,
BigInt(amount), BigInt(amount),
tryNativeToUint8Array(dstAddress, dstChain), tryNativeToUint8Array(dstAddress, chainToChainId(dstChain)),
dstChain, chainToChainId(dstChain),
BigInt(0) BigInt(0)
); );
const result = await nearAccount.functionCall(msg); const result = await nearAccount.functionCall(msg);
@ -207,8 +210,8 @@ export async function transferNear(
token_bridge, token_bridge,
tokenAddress, tokenAddress,
BigInt(amount), BigInt(amount),
tryNativeToUint8Array(dstAddress, dstChain), tryNativeToUint8Array(dstAddress, chainToChainId(dstChain)),
dstChain, chainToChainId(dstChain),
BigInt(0) BigInt(0)
); );
for (const msg of msgs) { for (const msg of msgs) {

315
clients/js/src/sdk/array.ts Normal file
View File

@ -0,0 +1,315 @@
import { arrayify, zeroPad } from "@ethersproject/bytes";
import { PublicKey } from "@solana/web3.js";
import {
hexValue,
hexZeroPad,
keccak256,
sha256,
stripZeros,
} from "ethers/lib/utils";
import { bech32 } from "bech32";
import {
Chain,
ChainId,
chainToChainId,
chainToPlatform,
toChain,
toChainId,
} from "@wormhole-foundation/sdk-base";
import {
PlatformToChains,
UniversalAddress,
encoding,
} from "@wormhole-foundation/sdk";
import { isValidSuiAddress } from "@mysten/sui.js";
import { sha3_256 } from "js-sha3";
import {
nativeStringToHexAlgorand,
uint8ArrayToNativeStringAlgorand,
} from "@certusone/wormhole-sdk/lib/esm/algorand";
import { isValidSuiType } from "@certusone/wormhole-sdk/lib/esm/sui";
/**
*
* Returns true iff the hex string represents a native Terra denom.
*
* Native assets on terra don't have an associated smart contract address, just
* like eth isn't an ERC-20 contract on Ethereum.
*
* The difference is that the EVM implementations of Portal don't support eth
* directly, and instead require swapping to an ERC-20 wrapped eth (WETH)
* contract first.
*
* The Terra implementation instead supports Terra-native denoms without
* wrapping to CW-20 token first. As these denoms don't have an address, they
* are encoded in the Portal payloads by the setting the first byte to 1. This
* encoding is safe, because the first 12 bytes of the 32-byte wormhole address
* space are not used on Terra otherwise, as cosmos addresses are 20 bytes wide.
*/
export const isHexNativeTerra = (h: string): boolean => h.startsWith("01");
const isLikely20ByteCosmwasm = (h: string): boolean =>
h.startsWith("000000000000000000000000");
export const nativeTerraHexToDenom = (h: string): string =>
Buffer.from(stripZeros(hexToUint8Array(h.substr(2)))).toString("ascii");
export const isNativeDenom = (string = "") =>
isNativeTerra(string) || string === "uluna";
export const isNativeTerra = (string = "") =>
string.startsWith("u") && string.length === 4;
export const uint8ArrayToHex = (a: Uint8Array): string =>
encoding.hex.encode(a);
export const hexToUint8Array = (h: string): Uint8Array =>
encoding.hex.decode(h);
export function canonicalAddress(humanAddress: string) {
return new Uint8Array(bech32.fromWords(bech32.decode(humanAddress).words));
}
export function humanAddress(hrp: string, canonicalAddress: Uint8Array) {
return bech32.encode(hrp, bech32.toWords(canonicalAddress));
}
export function buildTokenId(
chain: Exclude<PlatformToChains<"Cosmwasm">, "Terra">,
address: string
) {
return (
(isNativeCosmWasmDenom(chain, address) ? "01" : "00") +
keccak256(Buffer.from(address, "utf-8")).substring(4)
);
}
/**
*
* Convert an address in a wormhole's 32-byte array representation into a chain's
* native string representation.
*
* @throws if address is not the right length for the given chain
*/
export const tryUint8ArrayToNative = (
a: Uint8Array,
chain: ChainId | Chain
): string => {
const chainName = toChain(chain);
if (chainToPlatform(chainName) === "Evm") {
// if (isEVMChain(chainId)) {
return hexZeroPad(hexValue(a), 20);
} else if (chainToPlatform(chainName) === "Solana") {
return new PublicKey(a).toString();
} else if (chainName === "Terra" || chainName === "Terra2") {
const h = uint8ArrayToHex(a);
if (isHexNativeTerra(h)) {
return nativeTerraHexToDenom(h);
} else {
if (chainName === "Terra2" && !isLikely20ByteCosmwasm(h)) {
// terra 2 has 32 byte addresses for contracts and 20 for wallets
return humanAddress("terra", a);
}
return humanAddress("terra", a.slice(-20));
}
} else if (chainName === "Injective") {
const h = uint8ArrayToHex(a);
return humanAddress("inj", isLikely20ByteCosmwasm(h) ? a.slice(-20) : a);
} else if (chainName === "Algorand") {
return uint8ArrayToNativeStringAlgorand(a);
} else if (chainName == "Wormchain") {
const h = uint8ArrayToHex(a);
return humanAddress(
"wormhole",
isLikely20ByteCosmwasm(h) ? a.slice(-20) : a
);
} else if (chainName === "Xpla") {
const h = uint8ArrayToHex(a);
return humanAddress("xpla", isLikely20ByteCosmwasm(h) ? a.slice(-20) : a);
} else if (chainName === "Sei") {
const h = uint8ArrayToHex(a);
return humanAddress("sei", isLikely20ByteCosmwasm(h) ? a.slice(-20) : a);
} else if (chainName === "Near") {
throw Error("uint8ArrayToNative: Use tryHexToNativeStringNear instead.");
} else if (chainName === "Osmosis") {
throw Error("uint8ArrayToNative: Osmosis not supported yet.");
} else if (chainName === "Cosmoshub") {
throw Error("uint8ArrayToNative: CosmosHub not supported yet.");
} else if (chainName === "Evmos") {
throw Error("uint8ArrayToNative: Evmos not supported yet.");
} else if (chainName === "Kujira") {
throw Error("uint8ArrayToNative: Kujira not supported yet.");
} else if (chainName === "Neutron") {
throw Error("uint8ArrayToNative: Neutron not supported yet.");
} else if (chainName === "Celestia") {
throw Error("uint8ArrayToNative: Celestia not supported yet.");
} else if (chainName === "Stargaze") {
throw Error("uint8ArrayToNative: Stargaze not supported yet.");
} else if (chainName === "Seda") {
throw Error("uint8ArrayToNative: Seda not supported yet.");
} else if (chainName === "Dymension") {
throw Error("uint8ArrayToNative: Dymension not supported yet.");
} else if (chainName === "Provenance") {
throw Error("uint8ArrayToNative: Provenance not supported yet.");
} else if (chainName === "Sui") {
throw Error("uint8ArrayToNative: Sui not supported yet.");
} else if (chainName === "Aptos") {
throw Error("uint8ArrayToNative: Aptos not supported yet.");
} else if (chainName === "Btc") {
throw Error("uint8ArrayToNative: Btc not supported");
} else {
// This case is never reached
// const _: never = chainName;
throw Error("Don't know how to convert address for chain " + chainName);
}
};
/**
*
* Convert an address in a wormhole's 32-byte hex representation into a chain's native
* string representation.
*
* @throws if address is not the right length for the given chain
*/
export const tryHexToNativeAssetString = (h: string, c: ChainId): string =>
c === chainToChainId("Algorand")
? // Algorand assets are represented by their asset ids, not an address
new UniversalAddress(h).toNative("Algorand").toBigInt().toString()
: new UniversalAddress(h).toNative(toChain(c)).toString();
/**
*
* Convert an address in a chain's native representation into a 32-byte hex string
* understood by wormhole (UniversalAddress).
*
* @throws if address is a malformed string for the given chain id
*/
export const tryNativeToHexString = (
address: string,
chain: ChainId | Chain
): string => {
const chainName = toChain(chain);
if (chainToPlatform(chainName) === "Evm") {
return uint8ArrayToHex(zeroPad(arrayify(address), 32));
} else if (chainToPlatform(chainName) === "Solana") {
return uint8ArrayToHex(zeroPad(new PublicKey(address).toBytes(), 32));
} else if (chainName === "Terra") {
if (isNativeDenom(address)) {
return (
"01" +
uint8ArrayToHex(
zeroPad(new Uint8Array(Buffer.from(address, "ascii")), 31)
)
);
} else {
return uint8ArrayToHex(zeroPad(canonicalAddress(address), 32));
}
} else if (
chainName === "Terra2" ||
chainName === "Injective" ||
chainName === "Xpla" ||
chainName === "Sei"
) {
return buildTokenId(chainName, address);
} else if (chainName === "Algorand") {
return nativeStringToHexAlgorand(address);
} else if (chainName == "Wormchain") {
return uint8ArrayToHex(zeroPad(canonicalAddress(address), 32));
} else if (chainName === "Near") {
return uint8ArrayToHex(arrayify(sha256(Buffer.from(address))));
} else if (chainName === "Sui") {
if (!isValidSuiType(address) && isValidSuiAddress(address)) {
return uint8ArrayToHex(
zeroPad(arrayify(address, { allowMissingPrefix: true }), 32)
);
}
throw Error("nativeToHexString: Sui types not supported yet.");
} else if (chainName === "Aptos") {
if (isValidAptosType(address)) {
return getExternalAddressFromType(address);
}
return uint8ArrayToHex(
zeroPad(arrayify(address, { allowMissingPrefix: true }), 32)
);
} else {
// If this case is reached
throw Error(`nativeToHexString: ${chainName} not supported yet.`);
}
};
/**
*
* Convert an address in a chain's native representation into a 32-byte array
* understood by wormhole.
*
* @throws if address is a malformed string for the given chain id
*/
export function tryNativeToUint8Array(
address: string,
chain: ChainId | Chain
): Uint8Array {
const chainId = toChainId(chain);
return hexToUint8Array(tryNativeToHexString(address, chainId));
}
export const isNativeDenomInjective = (denom: string) => denom === "inj";
export const isNativeDenomXpla = (denom: string) => denom === "axpla";
export const isNativeDenomSei = (denom: string) => denom === "usei";
export const isNativeDenomWormchain = (denom: string) => denom === "uworm";
export const isNativeDenomOsmosis = (denom: string) => denom === "uosmo";
export const isNativeDenomCosmosHub = (denom: string) => denom === "uatom";
export const isNativeDenomEvmos = (denom: string) =>
denom === "aevmos" || denom === "atevmos";
export const isNativeDenomKujira = (denom: string) => denom === "ukuji";
export const isNativeDenomNeutron = (denom: string) => denom === "untrn";
export const isNativeDenomCelestia = (denom: string) => denom === "utia";
export const isNativeDenomStargaze = (denom: string) => denom === "ustars";
export const isNativeDenomSeda = (denom: string) => denom === "aseda";
export const isNativeDenomDymension = (denom: string) => denom === "adym";
export const isNativeDenomProvenance = (denom: string) => denom === "nhash";
export function isNativeCosmWasmDenom(
chain: PlatformToChains<"Cosmwasm">,
address: string
) {
return (
((chain === "Terra" || chain === "Terra2") && isNativeDenom(address)) ||
(chain === "Injective" && isNativeDenomInjective(address)) ||
(chain === "Xpla" && isNativeDenomXpla(address)) ||
(chain === "Sei" && isNativeDenomSei(address)) ||
(chain === "Wormchain" && isNativeDenomWormchain(address)) ||
(chain === "Osmosis" && isNativeDenomOsmosis(address)) ||
(chain === "Cosmoshub" && isNativeDenomCosmosHub(address)) ||
(chain === "Evmos" && isNativeDenomEvmos(address)) ||
(chain === "Kujira" && isNativeDenomKujira(address)) ||
(chain === "Neutron" && isNativeDenomNeutron(address)) ||
(chain === "Celestia" && isNativeDenomCelestia(address)) ||
(chain === "Stargaze" && isNativeDenomStargaze(address)) ||
(chain === "Seda" && isNativeDenomSeda(address)) ||
(chain === "Dymension" && isNativeDenomDymension(address)) ||
(chain === "Provenance" && isNativeDenomProvenance(address))
);
}
/**
* Test if given string is a valid fully qualified type of moduleAddress::moduleName::structName.
* @param str String to test
* @returns Whether or not given string is a valid type
*/
export const isValidAptosType = (str: string): boolean =>
/^(0x)?[0-9a-fA-F]+::\w+::\w+$/.test(str);
/**
* Hashes the given type. Because fully qualified types are a concept unique to Aptos, this
* output acts as the address on other chains.
* @param fullyQualifiedType Fully qualified type on Aptos
* @returns External address corresponding to given type
*/
export const getExternalAddressFromType = (
fullyQualifiedType: string
): string => {
// hash the type so it fits into 32 bytes
return sha3_256(fullyQualifiedType);
};

130
clients/js/src/sdk/sui.ts Normal file
View File

@ -0,0 +1,130 @@
import {
JsonRpcProvider,
SuiObjectResponse,
isValidSuiAddress as isValidFullSuiAddress,
normalizeSuiAddress,
} from "@mysten/sui.js";
import { Chain, chainToChainId } from "@wormhole-foundation/sdk";
export async function getForeignAssetSui(
provider: JsonRpcProvider,
tokenBridgeStateObjectId: string,
originChain: Chain,
originAddress: Uint8Array
): Promise<string | null> {
const originChainId = chainToChainId(originChain);
return getTokenCoinType(
provider,
tokenBridgeStateObjectId,
originAddress,
originChainId
);
}
export const getTokenCoinType = async (
provider: JsonRpcProvider,
tokenBridgeStateObjectId: string,
tokenAddress: Uint8Array,
tokenChain: number
): Promise<string | null> => {
const tokenBridgeStateFields = await getObjectFields(
provider,
tokenBridgeStateObjectId
);
if (!tokenBridgeStateFields) {
throw new Error("Unable to fetch object fields from token bridge state");
}
const coinTypes = tokenBridgeStateFields?.token_registry?.fields?.coin_types;
const coinTypesObjectId = coinTypes?.fields?.id?.id;
if (!coinTypesObjectId) {
throw new Error("Unable to fetch coin types");
}
const keyType = getTableKeyType(coinTypes?.type);
if (!keyType) {
throw new Error("Unable to get key type");
}
const response = await provider.getDynamicFieldObject({
parentId: coinTypesObjectId,
name: {
type: keyType,
value: {
addr: [...tokenAddress],
chain: tokenChain,
},
},
});
if (response.error) {
if (response.error.code === "dynamicFieldNotFound") {
return null;
}
throw new Error(
`Unexpected getDynamicFieldObject response ${response.error}`
);
}
const fields = getFieldsFromObjectResponse(response);
return fields?.value ? trimSuiType(ensureHexPrefix(fields.value)) : null;
};
export const getObjectFields = async (
provider: JsonRpcProvider,
objectId: string
): Promise<Record<string, any> | null> => {
if (!isValidSuiAddress(objectId)) {
throw new Error(`Invalid object ID: ${objectId}`);
}
const res = await provider.getObject({
id: objectId,
options: {
showContent: true,
},
});
return getFieldsFromObjectResponse(res);
};
export const getFieldsFromObjectResponse = (object: SuiObjectResponse) => {
const content = object.data?.content;
return content && content.dataType === "moveObject" ? content.fields : null;
};
export function ensureHexPrefix(x: string): string {
return x.substring(0, 2) !== "0x" ? `0x${x}` : x;
}
/**
* This method validates any Sui address, even if it's not 32 bytes long, i.e.
* "0x2". This differs from Mysten's implementation, which requires that the
* given address is 32 bytes long.
* @param address Address to check
* @returns If given address is a valid Sui address or not
*/
export const isValidSuiAddress = (address: string): boolean =>
isValidFullSuiAddress(normalizeSuiAddress(address));
export const getTableKeyType = (tableType: string): string | null => {
if (!tableType) return null;
const match = trimSuiType(tableType).match(/0x2::table::Table<(.*)>/);
if (!match) return null;
const [keyType] = match[1].split(",");
if (!isValidSuiType(keyType)) return null;
return keyType;
};
/**
* This method removes leading zeroes for types in order to normalize them
* since some types returned from the RPC have leading zeroes and others don't.
*/
export const trimSuiType = (type: string): string =>
type.replace(/(0x)(0*)/g, "0x");
export const isValidSuiType = (type: string): boolean => {
const tokens = type.split("::");
if (tokens.length !== 3) {
return false;
}
return isValidSuiAddress(tokens[0]) && !!tokens[1] && !!tokens[2];
};

View File

@ -16,13 +16,6 @@ import {
createUpgradeGuardianSetInstruction, createUpgradeGuardianSetInstruction,
createUpgradeContractInstruction as createWormholeUpgradeContractInstruction, createUpgradeContractInstruction as createWormholeUpgradeContractInstruction,
} from "@certusone/wormhole-sdk/lib/esm/solana/wormhole"; } from "@certusone/wormhole-sdk/lib/esm/solana/wormhole";
import {
CHAINS,
CONTRACTS,
ChainName,
Network,
SolanaChainName,
} from "@certusone/wormhole-sdk/lib/esm/utils/consts";
import * as web3s from "@solana/web3.js"; import * as web3s from "@solana/web3.js";
import base58 from "bs58"; import base58 from "bs58";
import { NETWORKS } from "./consts"; import { NETWORKS } from "./consts";
@ -32,19 +25,30 @@ import {
transferFromSolana, transferFromSolana,
transferNativeSol, transferNativeSol,
} from "@certusone/wormhole-sdk/lib/esm/token_bridge/transfer"; } from "@certusone/wormhole-sdk/lib/esm/token_bridge/transfer";
import {
hexToUint8Array,
tryNativeToUint8Array,
} from "@certusone/wormhole-sdk/lib/esm/utils";
import { PublicKey } from "@solana/web3.js"; import { PublicKey } from "@solana/web3.js";
import { getAssociatedTokenAddress } from "@solana/spl-token"; import { getAssociatedTokenAddress } from "@solana/spl-token";
import {
Chain,
Network,
PlatformToChains,
chainToChainId,
chainToPlatform,
chains,
contracts,
platformToChains,
} from "@wormhole-foundation/sdk-base";
import { hexToUint8Array, tryNativeToUint8Array } from "./sdk/array";
export async function execute_solana( export async function execute_solana(
v: VAA<Payload>, v: VAA<Payload>,
vaa: Buffer, vaa: Buffer,
network: "MAINNET" | "TESTNET" | "DEVNET", network: Network,
chain: SolanaChainName chain: Chain
) { ) {
if (chainToPlatform(chain) !== "Solana") {
// This "Solana" platform, also, includes Pythnet
throw new Error("Invalid chain");
}
const { rpc, key } = NETWORKS[network][chain]; const { rpc, key } = NETWORKS[network][chain];
if (!key) { if (!key) {
throw Error(`No ${network} key defined for ${chain}`); throw Error(`No ${network} key defined for ${chain}`);
@ -57,22 +61,24 @@ export async function execute_solana(
const connection = setupConnection(rpc); const connection = setupConnection(rpc);
const from = web3s.Keypair.fromSecretKey(base58.decode(key)); const from = web3s.Keypair.fromSecretKey(base58.decode(key));
const contracts = CONTRACTS[network][chain]; const coreContract = contracts.coreBridge.get(network, chain);
if (!contracts.core) { if (!coreContract) {
throw new Error(`Core bridge address not defined for ${chain} ${network}`); throw new Error(`Core bridge address not defined for ${chain} ${network}`);
} }
if (!contracts.nft_bridge) { const nftContract = contracts.nftBridge.get(network, chain);
if (!nftContract) {
throw new Error(`NFT bridge address not defined for ${chain} ${network}`); throw new Error(`NFT bridge address not defined for ${chain} ${network}`);
} }
if (!contracts.token_bridge) { const tbContract = contracts.tokenBridge.get(network, chain);
if (!tbContract) {
throw new Error(`Token bridge address not defined for ${chain} ${network}`); throw new Error(`Token bridge address not defined for ${chain} ${network}`);
} }
const bridgeId = new web3s.PublicKey(contracts.core); const bridgeId = new web3s.PublicKey(coreContract);
const tokenBridgeId = new web3s.PublicKey(contracts.token_bridge); const tokenBridgeId = new web3s.PublicKey(tbContract);
const nftBridgeId = new web3s.PublicKey(contracts.nft_bridge); const nftBridgeId = new web3s.PublicKey(nftContract);
let ix: web3s.TransactionInstruction; let ix: web3s.TransactionInstruction;
switch (v.payload.module) { switch (v.payload.module) {
@ -163,7 +169,7 @@ export async function execute_solana(
break; break;
case "Transfer": case "Transfer":
console.log("Completing transfer"); console.log("Completing transfer");
if (payload.tokenChain === CHAINS[chain]) { if (payload.tokenChain === chainToChainId(chain)) {
ix = createCompleteTransferNativeInstruction( ix = createCompleteTransferNativeInstruction(
tokenBridgeId, tokenBridgeId,
bridgeId, bridgeId,
@ -228,14 +234,15 @@ export async function execute_solana(
} }
export async function transferSolana( export async function transferSolana(
srcChain: SolanaChainName, srcChain: PlatformToChains<"Solana">,
dstChain: ChainName, dstChain: Chain,
dstAddress: string, dstAddress: string,
tokenAddress: string, tokenAddress: string,
amount: string, amount: string,
network: Network, network: Network,
rpc: string rpc: string
) { ) {
platformToChains("Solana");
const { key } = NETWORKS[network][srcChain]; const { key } = NETWORKS[network][srcChain];
if (!key) { if (!key) {
throw Error(`No ${network} key defined for ${srcChain}`); throw Error(`No ${network} key defined for ${srcChain}`);
@ -244,12 +251,13 @@ export async function transferSolana(
const connection = setupConnection(rpc); const connection = setupConnection(rpc);
const keypair = web3s.Keypair.fromSecretKey(base58.decode(key)); const keypair = web3s.Keypair.fromSecretKey(base58.decode(key));
const { core, token_bridge } = CONTRACTS[network][srcChain]; const core = contracts.coreBridge.get(network, srcChain);
if (!core) { if (!core) {
throw new Error( throw new Error(
`Core bridge address not defined for ${srcChain} ${network}` `Core bridge address not defined for ${srcChain} ${network}`
); );
} }
const token_bridge = contracts.tokenBridge.get(network, srcChain);
if (!token_bridge) { if (!token_bridge) {
throw new Error( throw new Error(
`Token bridge address not defined for ${srcChain} ${network}` `Token bridge address not defined for ${srcChain} ${network}`
@ -268,8 +276,8 @@ export async function transferSolana(
tokenBridgeId, tokenBridgeId,
payerAddress, payerAddress,
BigInt(amount), BigInt(amount),
tryNativeToUint8Array(dstAddress, dstChain), tryNativeToUint8Array(dstAddress, chainToChainId(dstChain)),
dstChain chainToChainId(dstChain)
); );
} else { } else {
// find the associated token account // find the associated token account
@ -287,8 +295,8 @@ export async function transferSolana(
fromAddress, fromAddress,
tokenAddress, // mintAddress tokenAddress, // mintAddress
BigInt(amount), BigInt(amount),
tryNativeToUint8Array(dstAddress, dstChain), tryNativeToUint8Array(dstAddress, chainToChainId(dstChain)),
dstChain chainToChainId(dstChain)
); );
} }
@ -316,18 +324,17 @@ export async function queryRegistrationsSolana(
network: Network, network: Network,
module: "Core" | "NFTBridge" | "TokenBridge" module: "Core" | "NFTBridge" | "TokenBridge"
): Promise<Object> { ): Promise<Object> {
const chain = "solana" as ChainName; const chain = "Solana";
const n = NETWORKS[network][chain]; const n = NETWORKS[network][chain];
const contracts = CONTRACTS[network][chain];
let targetAddress: string | undefined; let targetAddress: string | undefined;
switch (module) { switch (module) {
case "TokenBridge": case "TokenBridge":
targetAddress = contracts.token_bridge; targetAddress = contracts.tokenBridge(network, chain);
break; break;
case "NFTBridge": case "NFTBridge":
targetAddress = contracts.nft_bridge; targetAddress = contracts.nftBridge(network, chain);
break; break;
default: default:
throw new Error(`Invalid module: ${module}`); throw new Error(`Invalid module: ${module}`);
@ -346,26 +353,26 @@ export async function queryRegistrationsSolana(
// Query the bridge registration for all the chains in parallel. // Query the bridge registration for all the chains in parallel.
const registrations: (string | null)[][] = await Promise.all( const registrations: (string | null)[][] = await Promise.all(
Object.entries(CHAINS) chains
.filter(([cname, _]) => cname !== chain && cname !== "unset") .filter((cname) => cname !== chain)
.map(async ([cstr, cid]) => [ .map(async (cstr) => [
cstr, cstr,
await (async () => { await (async () => {
let cname = cstr as ChainName; // let cname = cstr as Chain;
let addr: string | undefined; let addr: string | undefined;
if (module === "TokenBridge") { if (module === "TokenBridge") {
addr = CONTRACTS[network][cname].token_bridge; addr = contracts.tokenBridge.get(network, cstr);
} else { } else {
addr = CONTRACTS[network][cname].nft_bridge; addr = contracts.nftBridge.get(network, cstr);
} }
if (addr === undefined) { if (addr === undefined) {
return null; return null;
} }
let emitter_addr = await getEmitterAddress(cname as ChainName, addr); let emitter_addr = await getEmitterAddress(cstr, addr);
const endpoint = deriveEndpointKey( const endpoint = deriveEndpointKey(
programId, programId,
cid, chainToChainId(cstr),
hexToUint8Array(emitter_addr) hexToUint8Array(emitter_addr)
); );

View File

@ -1,9 +1,3 @@
import {
CHAINS,
CONTRACTS,
ChainName,
TerraChainName,
} from "@certusone/wormhole-sdk/lib/esm/utils/consts";
import { import {
Coin, Coin,
Fee, Fee,
@ -15,24 +9,29 @@ import {
import axios from "axios"; import axios from "axios";
import { fromUint8Array } from "js-base64"; import { fromUint8Array } from "js-base64";
import { NETWORKS } from "./consts"; import { NETWORKS } from "./consts";
import { Network } from "./utils";
import { Payload, impossible } from "./vaa"; import { Payload, impossible } from "./vaa";
import { transferFromTerra } from "@certusone/wormhole-sdk/lib/esm/token_bridge/transfer"; import { transferFromTerra } from "@certusone/wormhole-sdk/lib/esm/token_bridge/transfer";
import { tryNativeToUint8Array } from "@certusone/wormhole-sdk/lib/esm/utils"; import {
Chain,
Network,
chains,
contracts,
toChainId,
} from "@wormhole-foundation/sdk-base";
import { tryNativeToUint8Array } from "./sdk/array";
export async function execute_terra( export async function execute_terra(
payload: Payload, payload: Payload,
vaa: Buffer, vaa: Buffer,
network: Network, network: Network,
chain: TerraChainName chain: "Terra" | "Terra2"
): Promise<void> { ): Promise<void> {
const { rpc, key, chain_id } = NETWORKS[network][chain]; const { rpc, key, chain_id } = NETWORKS[network][chain];
const contracts = CONTRACTS[network][chain];
const terra = new LCDClient({ const terra = new LCDClient({
URL: rpc, URL: rpc,
chainID: chain_id, chainID: chain_id,
isClassic: chain === "terra", isClassic: chain === "Terra",
}); });
const wallet = terra.wallet( const wallet = terra.wallet(
@ -46,13 +45,14 @@ export async function execute_terra(
switch (payload.module) { switch (payload.module) {
case "Core": { case "Core": {
if (!contracts.core) { const coreContract = contracts.coreBridge(network, chain);
if (!coreContract) {
throw new Error( throw new Error(
`Core bridge address not defined for ${chain} ${network}` `Core bridge address not defined for ${chain} ${network}`
); );
} }
target_contract = contracts.core; target_contract = coreContract;
// sigh... // sigh...
execute_msg = { execute_msg = {
submit_v_a_a: { submit_v_a_a: {
@ -75,14 +75,15 @@ export async function execute_terra(
break; break;
} }
case "NFTBridge": { case "NFTBridge": {
if (!contracts.nft_bridge) { const nftContract = contracts.nftBridge.get(network, chain);
if (!nftContract) {
// NOTE: this code can safely be removed once the terra NFT bridge is // NOTE: this code can safely be removed once the terra NFT bridge is
// released, but it's fine for it to stay, as the condition will just be // released, but it's fine for it to stay, as the condition will just be
// skipped once 'contracts.nft_bridge' is defined // skipped once 'contracts.nft_bridge' is defined
throw new Error(`NFT bridge not supported yet for ${chain}`); throw new Error(`NFT bridge not supported yet for ${chain}`);
} }
target_contract = contracts.nft_bridge; target_contract = nftContract;
execute_msg = { execute_msg = {
submit_vaa: { submit_vaa: {
data: fromUint8Array(vaa), data: fromUint8Array(vaa),
@ -107,13 +108,14 @@ export async function execute_terra(
break; break;
} }
case "TokenBridge": { case "TokenBridge": {
if (!contracts.token_bridge) { const tbContract = contracts.tokenBridge.get(network, chain);
if (!tbContract) {
throw new Error( throw new Error(
`Token bridge address not defined for ${chain} ${network}` `Token bridge address not defined for ${chain} ${network}`
); );
} }
target_contract = contracts.token_bridge; target_contract = tbContract;
execute_msg = { execute_msg = {
submit_vaa: { submit_vaa: {
data: fromUint8Array(vaa), data: fromUint8Array(vaa),
@ -160,8 +162,8 @@ export async function execute_terra(
} }
export async function transferTerra( export async function transferTerra(
srcChain: TerraChainName, srcChain: "Terra" | "Terra2",
dstChain: ChainName, dstChain: Chain,
dstAddress: string, dstAddress: string,
tokenAddress: string, tokenAddress: string,
amount: string, amount: string,
@ -172,7 +174,7 @@ export async function transferTerra(
if (!n.key) { if (!n.key) {
throw Error(`No ${network} key defined for ${srcChain} (see networks.ts)`); throw Error(`No ${network} key defined for ${srcChain} (see networks.ts)`);
} }
const { token_bridge } = CONTRACTS[network][srcChain]; const token_bridge = contracts.tokenBridge.get(network, srcChain);
if (!token_bridge) { if (!token_bridge) {
throw Error(`Unknown token bridge contract on ${network} for ${srcChain}`); throw Error(`Unknown token bridge contract on ${network} for ${srcChain}`);
} }
@ -180,7 +182,7 @@ export async function transferTerra(
const terra = new LCDClient({ const terra = new LCDClient({
URL: rpc, URL: rpc,
chainID: n.chain_id, chainID: n.chain_id,
isClassic: srcChain === "terra", isClassic: srcChain === "Terra",
}); });
const wallet = terra.wallet( const wallet = terra.wallet(
@ -194,8 +196,8 @@ export async function transferTerra(
token_bridge, token_bridge,
tokenAddress, tokenAddress,
amount, amount,
dstChain, toChainId(dstChain),
tryNativeToUint8Array(dstAddress, dstChain) tryNativeToUint8Array(dstAddress, toChainId(dstChain))
); );
await signAndSendTx(terra, wallet, msgs); await signAndSendTx(terra, wallet, msgs);
} }
@ -242,20 +244,19 @@ async function signAndSendTx(
export async function queryRegistrationsTerra( export async function queryRegistrationsTerra(
network: Network, network: Network,
chain: TerraChainName, chain: "Terra" | "Terra2",
module: "Core" | "NFTBridge" | "TokenBridge" module: "Core" | "NFTBridge" | "TokenBridge"
): Promise<Object> { ): Promise<Object> {
const n = NETWORKS[network][chain]; const n = NETWORKS[network][chain];
const contracts = CONTRACTS[network][chain];
let targetContract: string | undefined; let targetContract: string | undefined;
switch (module) { switch (module) {
case "TokenBridge": case "TokenBridge":
targetContract = contracts.token_bridge; targetContract = contracts.tokenBridge(network, chain);
break; break;
case "NFTBridge": case "NFTBridge":
targetContract = contracts.nft_bridge; targetContract = contracts.nftBridge.get(network, chain);
break; break;
default: default:
throw new Error(`Invalid module: ${module}`); throw new Error(`Invalid module: ${module}`);
@ -276,19 +277,19 @@ export async function queryRegistrationsTerra(
const client = new LCDClient({ const client = new LCDClient({
URL: n.rpc, URL: n.rpc,
chainID: n.chain_id, chainID: n.chain_id,
isClassic: chain === "terra", isClassic: chain === "Terra",
}); });
// Query the bridge registration for all the chains in parallel. // Query the bridge registration for all the chains in parallel.
const registrations: (string | null)[][] = await Promise.all( const registrations: (string | null)[][] = await Promise.all(
Object.entries(CHAINS) chains
.filter(([cname, _]) => cname !== chain && cname !== "unset") .filter((cname) => cname !== chain)
.map(async ([cname, cid]) => [ .map(async (cname) => [
cname, cname,
await (async () => { await (async () => {
let query_msg = { let query_msg = {
chain_registration: { chain_registration: {
chain: cid, chain: toChainId(cname),
}, },
}; };

View File

@ -0,0 +1,76 @@
// > paul@W7windows:~$ worm evm info -n mainnet -c ethereum -m TokenBridge
// {
// "address": "0x3ee18B2214AFF97000D974cf647E7C347E8fa585",
// "wormhole": "0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B",
// "implementation": "0x381752f5458282d317d12C30D2Bd4D6E1FD8841e",
// "isInitialized": true,
// "tokenImplementation": "0x0fD04a68d3c3A692d6Fa30384D1A87Ef93554eE6",
// "chainId": 2,
// "finality": 1,
// "evmChainId": "1",
// "isFork": false,
// "governanceChainId": 1,
// "governanceContract": "0x0000000000000000000000000000000000000000000000000000000000000004",
// "WETH": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
// "registrations": {
// "solana": "0xec7372995d5cc8732397fb0ad35c0121e0eaa90d26f828a534cab54391b3a4f5",
// "terra": "0x0000000000000000000000007cf7b764e38a0a5e967972c1df77d432510564e2",
// "bsc": "0x000000000000000000000000b6f6d86a8f9879a9c87f643768d9efc38c1da6e7",
// "polygon": "0x0000000000000000000000005a58505a96d1dbf8df91cb21b54419fc36e93fde",
// "avalanche": "0x0000000000000000000000000e082f06ff657d94310cb8ce8b0d9a04541d8052",
// "oasis": "0x0000000000000000000000005848c791e09901b40a9ef749f2a6735b418d7564",
// "algorand": "0x67e93fa6c8ac5c819990aa7340c0c16b508abb1178be9b30d024b8ac25193d45",
// "aurora": "0x00000000000000000000000051b5123a7b0f9b2ba265f9c4c8de7d78d52f510f",
// "fantom": "0x0000000000000000000000007c9fc5741288cdfdd83ceb07f3ea7e22618d79d2",
// "karura": "0x000000000000000000000000ae9d7fe007b3327aa64a32824aaac52c42a6e624",
// "acala": "0x000000000000000000000000ae9d7fe007b3327aa64a32824aaac52c42a6e624",
// "klaytn": "0x0000000000000000000000005b08ac39eaed75c0439fc750d9fe7e1f9dd0193f",
// "celo": "0x000000000000000000000000796dff6d74f3e27060b71255fe517bfb23c93eed",
// "near": "0x148410499d3fcda4dcfd68a1ebfcdddda16ab28326448d4aae4d2f0465cdfcb7",
// "moonbeam": "0x000000000000000000000000b1731c586ca89a23809861c6103f0b96b3f57d92",
// "neon": "0x0000000000000000000000000000000000000000000000000000000000000000",
// "terra2": "0xa463ad028fb79679cfc8ce1efba35ac0e77b35080a1abe9bebe83461f176b0a3",
// "injective": "0x00000000000000000000000045dbea4617971d93188eda21530bc6503d153313",
// "osmosis": "0x0000000000000000000000000000000000000000000000000000000000000000",
// "sui": "0xccceeb29348f71bdd22ffef43a2a19c1f5b5e17c5cca5411529120182672ade5",
// "aptos": "0x0000000000000000000000000000000000000000000000000000000000000001",
// "arbitrum": "0x0000000000000000000000000b2402144bb366a632d14b83f244d2e0e21bd39c",
// "optimism": "0x0000000000000000000000001d68124e65fafc907325e3edbf8c4d84499daa8b",
// "gnosis": "0x0000000000000000000000000000000000000000000000000000000000000000",
// "pythnet": "0x0000000000000000000000000000000000000000000000000000000000000000",
// "xpla": "0x8f9cf727175353b17a5f574270e370776123d90fd74956ae4277962b4fdee24c",
// "btc": "0x0000000000000000000000000000000000000000000000000000000000000000",
// "base": "0x0000000000000000000000008d2de8d2f73f1f4cab472ac9a881c9b123c79627",
// "sei": "0x86c5fd957e2db8389553e1728f9c27964b22a8154091ccba54d75f4b10c61f5e",
// "rootstock": "0x0000000000000000000000000000000000000000000000000000000000000000",
// "scroll": "0x00000000000000000000000024850c6f61c438823f01b7a3bf2b89b72174fa9d",
// "mantle": "0x0000000000000000000000000000000000000000000000000000000000000000",
// "blast": "0x00000000000000000000000024850c6f61c438823f01b7a3bf2b89b72174fa9d",
// "xlayer": "0x0000000000000000000000000000000000000000000000000000000000000000",
// "linea": "0x0000000000000000000000000000000000000000000000000000000000000000",
// "berachain": "0x0000000000000000000000000000000000000000000000000000000000000000",
// "seievm": "0x0000000000000000000000000000000000000000000000000000000000000000",
// "wormchain": "0xaeb534c45c3049d380b9d9b966f9895f53abd4301bfaff407fa09dea8ae7a924",
// "cosmoshub": "0x0000000000000000000000000000000000000000000000000000000000000000",
// "evmos": "0x0000000000000000000000000000000000000000000000000000000000000000",
// "kujira": "0x0000000000000000000000000000000000000000000000000000000000000000",
// "neutron": "0x0000000000000000000000000000000000000000000000000000000000000000",
// "celestia": "0x0000000000000000000000000000000000000000000000000000000000000000",
// "stargaze": "0x0000000000000000000000000000000000000000000000000000000000000000",
// "seda": "0x0000000000000000000000000000000000000000000000000000000000000000",
// "dymension": "0x0000000000000000000000000000000000000000000000000000000000000000",
// "provenance": "0x0000000000000000000000000000000000000000000000000000000000000000",
// "sepolia": "0x0000000000000000000000000000000000000000000000000000000000000000",
// "arbitrum_sepolia": "0x0000000000000000000000000000000000000000000000000000000000000000",
// "base_sepolia": "0x0000000000000000000000000000000000000000000000000000000000000000",
// "optimism_sepolia": "0x0000000000000000000000000000000000000000000000000000000000000000",
// "holesky": "0x0000000000000000000000000000000000000000000000000000000000000000",
// "polygon_sepolia": "0x0000000000000000000000000000000000000000000000000000000000000000"
// }
// }
// >>>worm info registrations mainnet ethereum TokenBridge -v
// Verification of ethereum MAINNET succeeded!
// >>>paul@W7windows:~$ worm info contract mainnet ethereum TokenBridge
// 0x3ee18B2214AFF97000D974cf647E7C347E8fa585

View File

@ -1,14 +1,14 @@
import {
Chain,
ChainId,
Network,
PlatformToChains,
chainToPlatform,
toChain,
} from "@wormhole-foundation/sdk-base";
import { spawnSync } from "child_process"; import { spawnSync } from "child_process";
import { ethers } from "ethers"; import { ethers } from "ethers";
export type Network = "MAINNET" | "TESTNET" | "DEVNET";
export function assertNetwork(n: string): asserts n is Network {
if (n !== "MAINNET" && n !== "TESTNET" && n !== "DEVNET") {
throw Error(`Unknown network: ${n}`);
}
}
export const checkBinary = (binaryName: string, readmeUrl?: string): void => { export const checkBinary = (binaryName: string, readmeUrl?: string): void => {
const binary = spawnSync(binaryName, ["--version"]); const binary = spawnSync(binaryName, ["--version"]);
if (binary.status !== 0) { if (binary.status !== 0) {
@ -29,3 +29,33 @@ export const evm_address = (x: string): string => {
export const hex = (x: string): string => { export const hex = (x: string): string => {
return ethers.utils.hexlify(x, { allowMissingPrefix: true }); return ethers.utils.hexlify(x, { allowMissingPrefix: true });
}; };
export function assertEVMChain(
chain: ChainId | Chain
): asserts chain is PlatformToChains<"Evm"> {
if (chainToPlatform(toChain(chain)) !== "Evm") {
throw Error(`Expected an EVM chain, but ${chain} is not`);
}
}
export function getNetwork(network: string): Network {
const lcNetwork: string = network.toLowerCase();
if (lcNetwork === "mainnet") {
return "Mainnet";
}
if (lcNetwork === "testnet") {
return "Testnet";
}
if (lcNetwork === "devnet") {
return "Devnet";
}
throw new Error(`Unknown network: ${network}`);
}
export function chainToChain(input: string): Chain {
if (input.length < 2) {
throw new Error(`Invalid chain: ${input}`);
}
const chainStr = input[0].toUpperCase() + input.slice(1).toLowerCase();
return toChain(chainStr);
}

View File

@ -1,7 +1,3 @@
import {
CONTRACTS,
ChainName,
} from "@certusone/wormhole-sdk/lib/esm/utils/consts";
import { import {
Coin, Coin,
Fee, Fee,
@ -12,18 +8,22 @@ import {
} from "@xpla/xpla.js"; } from "@xpla/xpla.js";
import { fromUint8Array } from "js-base64"; import { fromUint8Array } from "js-base64";
import { NETWORKS } from "./consts"; import { NETWORKS } from "./consts";
import { Network } from "./utils";
import { Payload, impossible } from "./vaa"; import { Payload, impossible } from "./vaa";
import { transferFromXpla } from "@certusone/wormhole-sdk/lib/esm/token_bridge/transfer"; import { transferFromXpla } from "@certusone/wormhole-sdk/lib/esm/token_bridge/transfer";
import { tryNativeToUint8Array } from "@certusone/wormhole-sdk/lib/esm/utils"; import {
Chain,
chainToChainId,
contracts,
Network,
} from "@wormhole-foundation/sdk-base";
import { tryNativeToUint8Array } from "./sdk/array";
export async function execute_xpla( export async function execute_xpla(
payload: Payload, payload: Payload,
vaa: Buffer, vaa: Buffer,
network: Network network: Network
) { ) {
const { rpc, key, chain_id } = NETWORKS[network].xpla; const { rpc, key, chain_id } = NETWORKS[network].Xpla;
const contracts = CONTRACTS[network].xpla;
if (!key) { if (!key) {
throw Error(`No ${network} key defined for XPLA`); throw Error(`No ${network} key defined for XPLA`);
} }
@ -47,11 +47,12 @@ export async function execute_xpla(
let execute_msg: object; let execute_msg: object;
switch (payload.module) { switch (payload.module) {
case "Core": { case "Core": {
if (!contracts.core) { const coreContract = contracts.coreBridge.get(network, "Xpla");
if (!coreContract) {
throw new Error(`Core bridge address not defined for XPLA ${network}`); throw new Error(`Core bridge address not defined for XPLA ${network}`);
} }
target_contract = contracts.core; target_contract = coreContract;
execute_msg = { execute_msg = {
submit_v_a_a: { submit_v_a_a: {
vaa: fromUint8Array(vaa), vaa: fromUint8Array(vaa),
@ -73,14 +74,15 @@ export async function execute_xpla(
break; break;
} }
case "NFTBridge": { case "NFTBridge": {
if (!contracts.nft_bridge) { const nftContract = contracts.nftBridge.get(network, "Xpla");
if (!nftContract) {
// NOTE: this code can safely be removed once the terra NFT bridge is // NOTE: this code can safely be removed once the terra NFT bridge is
// released, but it's fine for it to stay, as the condition will just be // released, but it's fine for it to stay, as the condition will just be
// skipped once 'contracts.nft_bridge' is defined // skipped once 'contracts.nft_bridge' is defined
throw new Error("NFT bridge not supported yet for XPLA"); throw new Error("NFT bridge not supported yet for XPLA");
} }
target_contract = contracts.nft_bridge; target_contract = nftContract;
execute_msg = { execute_msg = {
submit_vaa: { submit_vaa: {
data: fromUint8Array(vaa), data: fromUint8Array(vaa),
@ -105,11 +107,12 @@ export async function execute_xpla(
break; break;
} }
case "TokenBridge": { case "TokenBridge": {
if (!contracts.token_bridge) { const tbContract = contracts.tokenBridge.get(network, "Xpla");
if (!tbContract) {
throw new Error(`Token bridge address not defined for XPLA ${network}`); throw new Error(`Token bridge address not defined for XPLA ${network}`);
} }
target_contract = contracts.token_bridge; target_contract = tbContract;
execute_msg = { execute_msg = {
submit_vaa: { submit_vaa: {
data: fromUint8Array(vaa), data: fromUint8Array(vaa),
@ -156,18 +159,18 @@ export async function execute_xpla(
} }
export async function transferXpla( export async function transferXpla(
dstChain: ChainName, dstChain: Chain,
dstAddress: string, dstAddress: string,
tokenAddress: string, tokenAddress: string,
amount: string, amount: string,
network: Network, network: Network,
rpc: string rpc: string
) { ) {
const { key, chain_id } = NETWORKS[network].xpla; const { key, chain_id } = NETWORKS[network].Xpla;
if (!key) { if (!key) {
throw Error(`No ${network} key defined for XPLA`); throw Error(`No ${network} key defined for XPLA`);
} }
const { token_bridge } = CONTRACTS[network].xpla; const token_bridge = contracts.tokenBridge.get(network, "Xpla");
if (token_bridge == undefined) { if (token_bridge == undefined) {
throw Error(`Unknown token bridge contract on ${network} for XPLA`); throw Error(`Unknown token bridge contract on ${network} for XPLA`);
} }
@ -185,8 +188,8 @@ export async function transferXpla(
token_bridge, token_bridge,
tokenAddress, tokenAddress,
amount, amount,
dstChain, chainToChainId(dstChain),
tryNativeToUint8Array(dstAddress, dstChain) tryNativeToUint8Array(dstAddress, chainToChainId(dstChain))
); );
await signAndSendTx(client, wallet, msgs); await signAndSendTx(client, wallet, msgs);
} }

View File

@ -6,6 +6,7 @@
"outDir": "./build", "outDir": "./build",
"moduleResolution": "node", "moduleResolution": "node",
"esModuleInterop": true, "esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true, "forceConsistentCasingInFileNames": true,
"strict": true "strict": true
}, },