cli: Refactor js cli to support all contracts + add improvements (#1100)
* cli: Refactor js cli to support all contracts + add improvements * Fix path in Makefile * Don't be strict * Fix registration VAA deserialisation * Add karura gas calculation logic * cli: fix after sdk rebase * cli: improve makefile * cli: depend on @certusone/wormhole-sdk locally instead of importing relative paths * cli: add polygon overrides * client: update for devnet * fix tx signing in solana cli * client: alias network Co-authored-by: Csongor Kiss <ckiss@jumptrading.com> Co-authored-by: Evan Gray <battledingo@gmail.com>
This commit is contained in:
parent
c626e591e8
commit
1c006f9bed
|
@ -14,19 +14,11 @@ RUN --mount=type=cache,target=/root/.cache \
|
|||
ENV SOLANA_BIN_PATH="/root/.local/share/solana/install/active_release/bin"
|
||||
ENV PATH="$SOLANA_BIN_PATH:$PATH"
|
||||
|
||||
WORKDIR /usr/src/clients/token_bridge
|
||||
COPY clients/token_bridge/package.json clients/token_bridge/package-lock.json ./
|
||||
WORKDIR /usr/src/clients/js
|
||||
COPY clients/js/package.json clients/js/package-lock.json ./
|
||||
RUN --mount=type=cache,uid=1000,gid=1000,target=/home/node/.npm \
|
||||
npm ci
|
||||
COPY clients/token_bridge ./
|
||||
RUN npm run build
|
||||
|
||||
WORKDIR /usr/src/clients/nft_bridge
|
||||
COPY clients/nft_bridge/package.json clients/nft_bridge/package-lock.json ./
|
||||
RUN --mount=type=cache,uid=1000,gid=1000,target=/home/node/.npm \
|
||||
npm ci
|
||||
COPY clients/nft_bridge ./
|
||||
RUN npm run build
|
||||
COPY clients/js ./
|
||||
|
||||
ADD solana /usr/src/solana
|
||||
ADD proto /usr/src/proto
|
||||
|
|
|
@ -20,21 +20,13 @@ ENV NODE_OPTIONS=--use-openssl-ca
|
|||
RUN if [ -e /certs/cert.pem ]; then npm config set cafile /certs/cert.pem; fi
|
||||
|
||||
# install token_bridge deps & build
|
||||
WORKDIR /clients/token_bridge
|
||||
WORKDIR /clients/js
|
||||
# copy package.json & package-lock.json by themselves to create a cache layer
|
||||
COPY clients/token_bridge/package.json clients/token_bridge/package-lock.json ./
|
||||
COPY clients/js/package.json clients/js/package-lock.json ./
|
||||
# mount the buildkit cache on npm's cache dir, install dependencies
|
||||
RUN --mount=type=cache,target=/root/.npm npm ci
|
||||
# copy the rest of the source files, as a layer on top of the deps
|
||||
COPY clients/token_bridge ./
|
||||
RUN npm run build
|
||||
|
||||
# install nft_bridge deps & build
|
||||
WORKDIR /clients/nft_bridge
|
||||
COPY clients/nft_bridge/package.json clients/nft_bridge/package-lock.json ./
|
||||
RUN --mount=type=cache,target=/root/.npm npm ci
|
||||
COPY clients/nft_bridge ./
|
||||
RUN npm run build
|
||||
COPY clients/js ./
|
||||
|
||||
WORKDIR /
|
||||
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
INFURA_KEY=""
|
||||
ETH_KEY=""
|
||||
TERRA_MNEMONIC=""
|
||||
SOLANA_KEY=""
|
|
@ -0,0 +1 @@
|
|||
*.js
|
|
@ -0,0 +1,27 @@
|
|||
SOURCE_FILES:=$(shell find . -name "*.ts" -not -path "./node_modules/*")
|
||||
|
||||
.PHONY: all
|
||||
all: build
|
||||
|
||||
package-lock.json: package.json
|
||||
npm install
|
||||
|
||||
node_modules: package-lock.json
|
||||
@touch -m node_modules
|
||||
npm ci
|
||||
|
||||
.PHONY: dependencies
|
||||
dependencies: node_modules
|
||||
|
||||
build: node_modules $(SOURCE_FILES)
|
||||
@mkdir -p build
|
||||
@touch -m build
|
||||
npm run build
|
||||
|
||||
install: build
|
||||
@echo Linking binaries
|
||||
chmod +x build/main.js
|
||||
npm link
|
||||
|
||||
clean:
|
||||
rm -rf build node_modules
|
|
@ -0,0 +1,118 @@
|
|||
# Wormhole CLI
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
make install
|
||||
|
||||
This installs two binaries, `worm-fetch-governance` and `worm` on your `$PATH`.
|
||||
|
||||
## Usage
|
||||
|
||||
### `worm-fetch-governance`
|
||||
|
||||
Usage:
|
||||
worm-fetch-governance [sequence]
|
||||
|
||||
Fetch a governance VAA by sequence number, and print it as hex.
|
||||
|
||||
|
||||
For example
|
||||
|
||||
worm-fetch-governance 13940208096455381020
|
||||
|
||||
prints
|
||||
|
||||
01000000010d0012e6b39c6da90c5dfd3c228edbb78c7...
|
||||
|
||||
|
||||
### `worm`
|
||||
|
||||
This is the main CLI tool. To use it, set up `$HOME/.wormhole/.env` with your
|
||||
private keys, based on `.env.sample` in this folder.
|
||||
|
||||
worm [command]
|
||||
|
||||
Commands:
|
||||
worm generate generate VAAs (devnet and testnet only)
|
||||
worm parse <vaa> Parse a VAA
|
||||
worm submit <vaa> Execute a VAA
|
||||
|
||||
Options:
|
||||
--help Show help [boolean]
|
||||
--version Show version number [boolean]
|
||||
|
||||
Consult the `--help` flag for using subcommands.
|
||||
|
||||
Use `generate` to create VAAs for testing. For example, to create an NFT bridge registration VAA:
|
||||
|
||||
worm generate registration --module NFTBridge \
|
||||
--chain-id 2 \
|
||||
--contract-address 706abc4E45D419950511e474C7B9Ed348A4a716c \
|
||||
--guardian-secret cfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0
|
||||
|
||||
Use `parse` to parse a VAA into JSON. For example,
|
||||
|
||||
worm parse $(worm-fetch-governance 13940208096455381020)
|
||||
|
||||
will fetch governance VAA `13940208096455381020` and print it as JSON.
|
||||
|
||||
# ...signatures elided
|
||||
timestamp: 1651416474,
|
||||
nonce: 1570649151,
|
||||
emitterChain: 1,
|
||||
emitterAddress: '0000000000000000000000000000000000000000000000000000000000000004',
|
||||
sequence: 13940208096455381020n,
|
||||
consistencyLevel: 32,
|
||||
payload: {
|
||||
module: 'Core',
|
||||
type: 'GuardianSetUpgrade',
|
||||
chain: 0,
|
||||
newGuardianSetIndex: 2,
|
||||
newGuardianSetLength: 19,
|
||||
newGuardianSet: [
|
||||
'58cc3ae5c097b213ce3c81979e1b9f9570746aa5',
|
||||
'ff6cb952589bde862c25ef4392132fb9d4a42157',
|
||||
'114de8460193bdf3a2fcf81f86a09765f4762fd1',
|
||||
'107a0086b32d7a0977926a205131d8731d39cbeb',
|
||||
'8c82b2fd82faed2711d59af0f2499d16e726f6b2',
|
||||
'11b39756c042441be6d8650b69b54ebe715e2343',
|
||||
'54ce5b4d348fb74b958e8966e2ec3dbd4958a7cd',
|
||||
'66b9590e1c41e0b226937bf9217d1d67fd4e91f5',
|
||||
'74a3bf913953d695260d88bc1aa25a4eee363ef0',
|
||||
'000ac0076727b35fbea2dac28fee5ccb0fea768e',
|
||||
'af45ced136b9d9e24903464ae889f5c8a723fc14',
|
||||
'f93124b7c738843cbb89e864c862c38cddcccf95',
|
||||
'd2cc37a4dc036a8d232b48f62cdd4731412f4890',
|
||||
'da798f6896a3331f64b48c12d1d57fd9cbe70811',
|
||||
'71aa1be1d36cafe3867910f99c09e347899c19c3',
|
||||
'8192b6e7387ccd768277c17dab1b7a5027c0b3cf',
|
||||
'178e21ad2e77ae06711549cfbb1f9c7a9d8096e8',
|
||||
'5e1487f35515d02a92753504a8d75471b9f49edb',
|
||||
'6fbebc898f403e4773e95feb15e80c9a99c8348d'
|
||||
]
|
||||
}
|
||||
|
||||
Use `submit` to submit a VAA to a chain. It first parses the VAA and figures out
|
||||
what's the destination chain and module. For example, a contract upgrade contains both the target chain and module, so the only required argument is the network moniker (`mainnet` or `testnet`):
|
||||
|
||||
worm submit $(cat my-nft-registration.txt) --network mainnet
|
||||
|
||||
|
||||
For VAAs that don't have a specific target chain (like registrations or guardian
|
||||
set upgrades), the script will ask you to specify the target chain.
|
||||
For example, to submit a guardian set upgrade on all chains, simply run:
|
||||
|
||||
worm-fetch-governance 13940208096455381020 > guardian-upgrade.txt
|
||||
worm submit $(cat guardian-upgrade.txt) --network mainnet --chain oasis
|
||||
worm submit $(cat guardian-upgrade.txt) --network mainnet --chain aurora
|
||||
worm submit $(cat guardian-upgrade.txt) --network mainnet --chain fantom
|
||||
worm submit $(cat guardian-upgrade.txt) --network mainnet --chain karura
|
||||
worm submit $(cat guardian-upgrade.txt) --network mainnet --chain avalanche
|
||||
worm submit $(cat guardian-upgrade.txt) --network mainnet --chain polygon
|
||||
worm submit $(cat guardian-upgrade.txt) --network mainnet --chain bsc
|
||||
worm submit $(cat guardian-upgrade.txt) --network mainnet --chain solana
|
||||
worm submit $(cat guardian-upgrade.txt) --network mainnet --chain terra
|
||||
worm submit $(cat guardian-upgrade.txt) --network mainnet --chain ethereum
|
||||
|
||||
The VAA payload type (guardian set upgrade) specifies that this VAA should go to the core bridge, and the tool directs it there.
|
|
@ -0,0 +1,30 @@
|
|||
declare module 'elliptic' {
|
||||
export interface BN {
|
||||
length: number;
|
||||
negative: number;
|
||||
words: Uint8Array;
|
||||
toString(format: string?): string;
|
||||
}
|
||||
|
||||
export interface Point {
|
||||
x: BN;
|
||||
y: BN;
|
||||
}
|
||||
|
||||
export interface KeyPair {
|
||||
getPrivate(): BN;
|
||||
getPublic(): Point;
|
||||
sign(message: Buffer, options: any): {
|
||||
r: BN,
|
||||
s: BN,
|
||||
recoveryParam: number
|
||||
};
|
||||
}
|
||||
|
||||
export class ec {
|
||||
constructor(curveName: string);
|
||||
genKeyPair(): KeyPair;
|
||||
keyFromPrivate(priv: any, enc?: any): KeyPair;
|
||||
keyFromPublic(priv: any, enc: any): KeyPair;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
import { BridgeImplementation__factory, Implementation__factory, NFTBridgeImplementation__factory } from "@certusone/wormhole-sdk"
|
||||
import { ethers } from "ethers"
|
||||
import { NETWORKS } from "./networks"
|
||||
import { impossible, Payload } from "./vaa"
|
||||
import { Contracts, CONTRACTS, EVMChainName } from "@certusone/wormhole-sdk"
|
||||
import axios from "axios";
|
||||
|
||||
export async function execute_governance_evm(
|
||||
payload: Payload,
|
||||
vaa: Buffer,
|
||||
network: "MAINNET" | "TESTNET" | "DEVNET",
|
||||
chain: EVMChainName
|
||||
) {
|
||||
let n = NETWORKS[network][chain]
|
||||
if (!n.rpc) {
|
||||
throw Error(`No ${network} rpc defined for ${chain} (see networks.ts)`)
|
||||
}
|
||||
if (!n.key) {
|
||||
throw Error(`No ${network} key defined for ${chain} (see networks.ts)`)
|
||||
}
|
||||
let rpc: string = n.rpc
|
||||
let key: string = n.key
|
||||
|
||||
let contracts: Contracts = CONTRACTS[network][chain]
|
||||
|
||||
let provider = new ethers.providers.JsonRpcProvider(rpc)
|
||||
let signer = new ethers.Wallet(key, provider)
|
||||
|
||||
// Here we apply a set of chain-specific overrides.
|
||||
// NOTE: some of these might have only been tested on mainnet. If it fails in
|
||||
// testnet (or devnet), they might require additional guards
|
||||
let overrides: ethers.Overrides = {}
|
||||
if (chain === "karura") {
|
||||
overrides = await getKaruraGasParams(n.rpc)
|
||||
} else if (chain === "polygon") {
|
||||
let feeData = await provider.getFeeData();
|
||||
overrides = {
|
||||
maxFeePerGas: feeData.maxFeePerGas?.mul(50) || undefined,
|
||||
maxPriorityFeePerGas: feeData.maxPriorityFeePerGas?.mul(50) || undefined,
|
||||
};
|
||||
}
|
||||
|
||||
switch (payload.module) {
|
||||
case "Core":
|
||||
if (contracts.core === undefined) {
|
||||
throw Error(`Unknown core contract on ${network} for ${chain}`)
|
||||
}
|
||||
let c = new Implementation__factory(signer)
|
||||
let cb = c.attach(contracts.core)
|
||||
switch (payload.type) {
|
||||
case "GuardianSetUpgrade":
|
||||
console.log("Submitting new guardian set")
|
||||
console.log("Hash: " + (await cb.submitNewGuardianSet(vaa, overrides)).hash)
|
||||
break
|
||||
case "ContractUpgrade":
|
||||
console.log("Upgrading core contract")
|
||||
console.log("Hash: " + (await cb.submitContractUpgrade(vaa, overrides)).hash)
|
||||
break
|
||||
default:
|
||||
impossible(payload)
|
||||
}
|
||||
break
|
||||
case "NFTBridge":
|
||||
if (contracts.nft_bridge === undefined) {
|
||||
throw Error(`Unknown nft bridge contract on ${network} for ${chain}`)
|
||||
}
|
||||
let n = new NFTBridgeImplementation__factory(signer)
|
||||
let nb = n.attach(contracts.nft_bridge)
|
||||
switch (payload.type) {
|
||||
case "ContractUpgrade":
|
||||
console.log("Upgrading contract")
|
||||
console.log("Hash: " + (await nb.upgrade(vaa, overrides)).hash)
|
||||
console.log("Don't forget to verify the new implementation! See ethereum/VERIFY.md for instructions")
|
||||
break
|
||||
case "RegisterChain":
|
||||
console.log("Registering chain")
|
||||
console.log("Hash: " + (await nb.registerChain(vaa, overrides)).hash)
|
||||
break
|
||||
default:
|
||||
impossible(payload)
|
||||
|
||||
}
|
||||
break
|
||||
case "TokenBridge":
|
||||
if (contracts.token_bridge === undefined) {
|
||||
throw Error(`Unknown token bridge contract on ${network} for ${chain}`)
|
||||
}
|
||||
let t = new BridgeImplementation__factory(signer)
|
||||
let tb = t.attach(contracts.token_bridge)
|
||||
switch (payload.type) {
|
||||
case "ContractUpgrade":
|
||||
console.log("Upgrading contract")
|
||||
console.log("Hash: " + (await tb.upgrade(vaa, overrides)).hash)
|
||||
console.log("Don't forget to verify the new implementation! See ethereum/VERIFY.md for instructions")
|
||||
break
|
||||
case "RegisterChain":
|
||||
console.log("Registering chain")
|
||||
console.log("Hash: " + (await tb.registerChain(vaa, overrides)).hash)
|
||||
break
|
||||
default:
|
||||
impossible(payload)
|
||||
|
||||
}
|
||||
break
|
||||
default:
|
||||
impossible(payload)
|
||||
}
|
||||
}
|
||||
|
||||
export async function getKaruraGasParams(rpc: string): Promise<{
|
||||
gasPrice: number;
|
||||
gasLimit: number;
|
||||
}> {
|
||||
const gasLimit = 21000000;
|
||||
const storageLimit = 64001;
|
||||
const res = (
|
||||
await axios.post(rpc, {
|
||||
id: 0,
|
||||
jsonrpc: "2.0",
|
||||
method: "eth_getEthGas",
|
||||
params: [
|
||||
{
|
||||
gasLimit,
|
||||
storageLimit,
|
||||
},
|
||||
],
|
||||
})
|
||||
).data.result;
|
||||
|
||||
return {
|
||||
gasLimit: parseInt(res.gasLimit, 16),
|
||||
gasPrice: parseInt(res.gasPrice, 16),
|
||||
};
|
||||
}
|
|
@ -0,0 +1,288 @@
|
|||
#!/usr/bin/env node
|
||||
import yargs from "yargs";
|
||||
|
||||
import { hideBin } from "yargs/helpers";
|
||||
|
||||
import { setDefaultWasm } from "@certusone/wormhole-sdk";
|
||||
import { execute_governance_solana } from "./solana";
|
||||
import { execute_governance_evm } from "./evm";
|
||||
import { execute_governance_terra } from "./terra";
|
||||
import * as vaa from "./vaa";
|
||||
import { impossible, Payload, serialiseVAA, VAA } from "./vaa";
|
||||
import {
|
||||
assertChain,
|
||||
ChainName,
|
||||
CHAINS,
|
||||
toChainName,
|
||||
isEVMChain,
|
||||
toChainId,
|
||||
} from "@certusone/wormhole-sdk";
|
||||
|
||||
setDefaultWasm("node");
|
||||
|
||||
const GOVERNANCE_CHAIN = 1;
|
||||
const GOVERNANCE_EMITTER =
|
||||
"0000000000000000000000000000000000000000000000000000000000000004";
|
||||
|
||||
function makeVAA(
|
||||
emitterChain: number,
|
||||
emitterAddress: string,
|
||||
signers: string[],
|
||||
p: Payload
|
||||
): VAA<Payload> {
|
||||
let v: VAA<Payload> = {
|
||||
version: 1,
|
||||
guardianSetIndex: 0,
|
||||
signatures: [],
|
||||
timestamp: 1,
|
||||
nonce: 1,
|
||||
emitterChain: emitterChain,
|
||||
emitterAddress: emitterAddress,
|
||||
sequence: BigInt(Math.floor(Math.random() * 100000000)),
|
||||
consistencyLevel: 0,
|
||||
payload: p,
|
||||
};
|
||||
v.signatures = vaa.sign(signers, v);
|
||||
return v;
|
||||
}
|
||||
|
||||
yargs(hideBin(process.argv))
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Generate
|
||||
.command(
|
||||
"generate",
|
||||
"generate VAAs (devnet and testnet only)",
|
||||
(yargs) => {
|
||||
return (
|
||||
yargs
|
||||
.option("guardian-secret", {
|
||||
alias: "g",
|
||||
required: true,
|
||||
describe: "Guardians' secret keys",
|
||||
type: "string",
|
||||
})
|
||||
// Registration
|
||||
.command(
|
||||
"registration",
|
||||
"Generate registration VAA",
|
||||
(yargs) => {
|
||||
return yargs
|
||||
.option("chain", {
|
||||
alias: "c",
|
||||
describe: "Chain to register",
|
||||
type: "string",
|
||||
choices: Object.keys(CHAINS),
|
||||
required: true,
|
||||
})
|
||||
.option("contract-address", {
|
||||
alias: "a",
|
||||
describe: "Contract to register",
|
||||
type: "string",
|
||||
required: true,
|
||||
})
|
||||
.option("module", {
|
||||
alias: "m",
|
||||
describe: "Module to upgrade",
|
||||
type: "string",
|
||||
choices: ["NFTBridge", "TokenBridge"],
|
||||
required: true,
|
||||
});
|
||||
},
|
||||
(argv) => {
|
||||
let module = argv["module"] as "NFTBridge" | "TokenBridge";
|
||||
assertChain(argv["chain"]);
|
||||
let payload: vaa.PortalRegisterChain<typeof module> = {
|
||||
module,
|
||||
type: "RegisterChain",
|
||||
chain: 0,
|
||||
emitterChain: toChainId(argv["chain"]),
|
||||
emitterAddress: Buffer.from(
|
||||
argv["contract-address"].padStart(64, "0"),
|
||||
"hex"
|
||||
),
|
||||
};
|
||||
let v = makeVAA(
|
||||
GOVERNANCE_CHAIN,
|
||||
GOVERNANCE_EMITTER,
|
||||
argv["guardian-secret"].split(","),
|
||||
payload
|
||||
);
|
||||
console.log(serialiseVAA(v));
|
||||
}
|
||||
)
|
||||
// Upgrade
|
||||
.command(
|
||||
"upgrade",
|
||||
"Generate contract upgrade VAA",
|
||||
(yargs) => {
|
||||
return yargs
|
||||
.option("chain", {
|
||||
alias: "c",
|
||||
describe: "Chain to upgrade",
|
||||
type: "string",
|
||||
choices: Object.keys(CHAINS),
|
||||
required: true,
|
||||
})
|
||||
.option("contract-address", {
|
||||
alias: "a",
|
||||
describe: "Contract to upgrade to",
|
||||
type: "string",
|
||||
required: true,
|
||||
})
|
||||
.option("module", {
|
||||
alias: "m",
|
||||
describe: "Module to upgrade",
|
||||
type: "string",
|
||||
choices: ["Core", "NFTBridge", "TokenBridge"],
|
||||
required: true,
|
||||
});
|
||||
},
|
||||
(argv) => {
|
||||
assertChain(argv["chain"]);
|
||||
let module = argv["module"] as
|
||||
| "Core"
|
||||
| "NFTBridge"
|
||||
| "TokenBridge";
|
||||
let payload: Payload = {
|
||||
module,
|
||||
type: "ContractUpgrade",
|
||||
chain: toChainId(argv["chain"]),
|
||||
address: Buffer.from(
|
||||
argv["contract-address"].padStart(64, "0"),
|
||||
"hex"
|
||||
),
|
||||
};
|
||||
let v = makeVAA(
|
||||
GOVERNANCE_CHAIN,
|
||||
GOVERNANCE_EMITTER,
|
||||
argv["guardian-secret"].split(","),
|
||||
payload
|
||||
);
|
||||
console.log(serialiseVAA(v));
|
||||
}
|
||||
)
|
||||
);
|
||||
},
|
||||
(_) => {
|
||||
yargs.showHelp();
|
||||
}
|
||||
)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Parse
|
||||
.command(
|
||||
"parse <vaa>",
|
||||
"Parse a VAA",
|
||||
(yargs) => {
|
||||
return yargs.positional("vaa", {
|
||||
describe: "vaa",
|
||||
type: "string",
|
||||
});
|
||||
},
|
||||
async (argv) => {
|
||||
const buf = Buffer.from(String(argv.vaa), "hex");
|
||||
const parsed_vaa = vaa.parse(buf);
|
||||
console.log(parsed_vaa);
|
||||
}
|
||||
)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Submit
|
||||
.command(
|
||||
"submit <vaa>",
|
||||
"Execute a VAA",
|
||||
(yargs) => {
|
||||
return yargs
|
||||
.positional("vaa", {
|
||||
describe: "vaa",
|
||||
type: "string",
|
||||
required: true,
|
||||
})
|
||||
.option("chain", {
|
||||
alias: "c",
|
||||
describe: "chain name",
|
||||
type: "string",
|
||||
choices: Object.keys(CHAINS),
|
||||
required: false,
|
||||
})
|
||||
.option("network", {
|
||||
alias: "n",
|
||||
describe: "network",
|
||||
type: "string",
|
||||
choices: ["mainnet", "testnet", "devnet"],
|
||||
required: true,
|
||||
});
|
||||
},
|
||||
async (argv) => {
|
||||
const vaa_hex = String(argv.vaa);
|
||||
const buf = Buffer.from(vaa_hex, "hex");
|
||||
const parsed_vaa = vaa.parse(buf);
|
||||
|
||||
if (!vaa.hasPayload(parsed_vaa)) {
|
||||
throw Error("Couldn't parse VAA payload");
|
||||
}
|
||||
|
||||
console.log(parsed_vaa.payload);
|
||||
|
||||
const network = argv.network.toUpperCase();
|
||||
if (
|
||||
network !== "MAINNET" &&
|
||||
network !== "TESTNET" &&
|
||||
network !== "DEVNET"
|
||||
) {
|
||||
throw Error(`Unknown network: ${network}`);
|
||||
}
|
||||
|
||||
// We figure out the target chain to submit the VAA to.
|
||||
// The VAA might specify this itself (for example a contract upgrade VAA
|
||||
// or a token transfer VAA), in which case we just submit the VAA to
|
||||
// that target chain.
|
||||
//
|
||||
// If the VAA does not have a target (e.g. chain registration VAAs or
|
||||
// guardian set upgrade VAAs), we require the '--chain' argument to be
|
||||
// set on the command line.
|
||||
//
|
||||
// As a sanity check, in the event that the VAA does specify a target
|
||||
// and the '--chain' argument is also set, we issue an error if those
|
||||
// two don't agree instead of silently taking the VAA's target chain.
|
||||
|
||||
// get VAA chain
|
||||
const vaa_chain_id = parsed_vaa.payload.chain;
|
||||
assertChain(vaa_chain_id);
|
||||
const vaa_chain = toChainName(vaa_chain_id);
|
||||
|
||||
// get chain from command line arg
|
||||
const cli_chain = argv["chain"];
|
||||
|
||||
let chain: ChainName;
|
||||
if (cli_chain !== undefined) {
|
||||
assertChain(cli_chain);
|
||||
if (vaa_chain !== "unset" && cli_chain !== vaa_chain) {
|
||||
throw Error(
|
||||
`Specified target chain (${cli_chain}) does not match VAA target chain (${vaa_chain})`
|
||||
);
|
||||
}
|
||||
chain = cli_chain;
|
||||
} else {
|
||||
chain = vaa_chain;
|
||||
}
|
||||
|
||||
if (chain === "unset") {
|
||||
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_governance_evm(parsed_vaa.payload, buf, network, chain);
|
||||
} else if (chain === "terra") {
|
||||
await execute_governance_terra(parsed_vaa.payload, buf, network);
|
||||
} else if (chain === "solana") {
|
||||
await execute_governance_solana(parsed_vaa, buf, network);
|
||||
} else if (chain === "algorand") {
|
||||
throw Error("Algorand is not supported yet");
|
||||
} else if (chain === "near") {
|
||||
throw Error("NEAR is not supported yet");
|
||||
} else {
|
||||
// If you get a type error here, hover over `chain`'s type and it tells you
|
||||
// which cases are not handled
|
||||
impossible(chain);
|
||||
}
|
||||
}
|
||||
).argv;
|
|
@ -0,0 +1,263 @@
|
|||
import { ChainName } from "@certusone/wormhole-sdk";
|
||||
|
||||
require("dotenv").config({ path: `${process.env.HOME}/.wormhole/.env` });
|
||||
|
||||
function get_env_var(env: string): string | undefined {
|
||||
const v = process.env[env];
|
||||
return v;
|
||||
}
|
||||
|
||||
export type Connection = {
|
||||
rpc: string | undefined;
|
||||
key: string | undefined;
|
||||
};
|
||||
|
||||
export type ChainConnections = {
|
||||
[chain in ChainName]: Connection;
|
||||
};
|
||||
|
||||
const MAINNET = {
|
||||
unset: {
|
||||
rpc: undefined,
|
||||
key: undefined,
|
||||
},
|
||||
solana: {
|
||||
rpc: "https://api.mainnet-beta.solana.com",
|
||||
key: get_env_var("SOLANA_KEY"),
|
||||
},
|
||||
terra: {
|
||||
rpc: "https://lcd.terra.dev",
|
||||
chain_id: "columbus-5",
|
||||
key: get_env_var("TERRA_MNEMONIC"),
|
||||
},
|
||||
ethereum: {
|
||||
rpc: `https://mainnet.infura.io/v3/${get_env_var("INFURA_KEY")}`,
|
||||
key: get_env_var("ETH_KEY"),
|
||||
},
|
||||
bsc: {
|
||||
rpc: "https://bsc-dataseed.binance.org/",
|
||||
key: get_env_var("ETH_KEY"),
|
||||
},
|
||||
polygon: {
|
||||
rpc: "https://polygon-rpc.com",
|
||||
key: get_env_var("ETH_KEY"),
|
||||
},
|
||||
avalanche: {
|
||||
rpc: "https://api.avax.network/ext/bc/C/rpc",
|
||||
key: get_env_var("ETH_KEY"),
|
||||
},
|
||||
algorand: {
|
||||
rpc: undefined,
|
||||
key: undefined,
|
||||
},
|
||||
oasis: {
|
||||
rpc: "https://emerald.oasis.dev/",
|
||||
key: get_env_var("ETH_KEY"),
|
||||
},
|
||||
fantom: {
|
||||
rpc: "https://rpc.ftm.tools/",
|
||||
key: get_env_var("ETH_KEY"),
|
||||
},
|
||||
aurora: {
|
||||
rpc: "https://mainnet.aurora.dev",
|
||||
key: get_env_var("ETH_KEY"),
|
||||
},
|
||||
karura: {
|
||||
rpc: "https://eth-rpc-karura.aca-api.network/",
|
||||
key: get_env_var("ETH_KEY"),
|
||||
},
|
||||
acala: {
|
||||
rpc: undefined,
|
||||
key: get_env_var("ETH_KEY"),
|
||||
},
|
||||
klaytn: {
|
||||
rpc: undefined,
|
||||
key: get_env_var("ETH_KEY"),
|
||||
},
|
||||
celo: {
|
||||
rpc: undefined,
|
||||
key: get_env_var("ETH_KEY"),
|
||||
},
|
||||
near: {
|
||||
rpc: undefined,
|
||||
key: undefined,
|
||||
},
|
||||
ropsten: {
|
||||
rpc: `https://ropsten.infura.io/v3/${get_env_var("INFURA_KEY")}`,
|
||||
key: get_env_var("ETH_KEY"),
|
||||
},
|
||||
};
|
||||
|
||||
const TESTNET = {
|
||||
unset: {
|
||||
rpc: undefined,
|
||||
key: undefined,
|
||||
},
|
||||
solana: {
|
||||
rpc: "https://api.devnet.solana.com",
|
||||
key: get_env_var("SOLANA_KEY"),
|
||||
},
|
||||
terra: {
|
||||
rpc: "https://bombay-lcd.terra.dev",
|
||||
chain_id: "bombay-12",
|
||||
key: get_env_var("TERRA_MNEMONIC"),
|
||||
},
|
||||
ethereum: {
|
||||
rpc: `https://goerli.infura.io/v3/${get_env_var("INFURA_KEY")}`,
|
||||
key: get_env_var("ETH_KEY"),
|
||||
},
|
||||
bsc: {
|
||||
rpc: "https://data-seed-prebsc-1-s1.binance.org:8545",
|
||||
key: get_env_var("ETH_KEY"),
|
||||
},
|
||||
polygon: {
|
||||
rpc: `https://polygon-mumbai.infura.io/v3/${get_env_var("INFURA_KEY")}`,
|
||||
key: get_env_var("ETH_KEY"),
|
||||
},
|
||||
avalanche: {
|
||||
rpc: "https://api.avax-test.network/ext/bc/C/rpc",
|
||||
key: get_env_var("ETH_KEY"),
|
||||
},
|
||||
oasis: {
|
||||
rpc: "https://testnet.emerald.oasis.dev",
|
||||
key: get_env_var("ETH_KEY"),
|
||||
},
|
||||
algorand: {
|
||||
rpc: undefined,
|
||||
key: undefined,
|
||||
},
|
||||
fantom: {
|
||||
rpc: "https://rpc.testnet.fantom.network",
|
||||
key: get_env_var("ETH_KEY"),
|
||||
},
|
||||
aurora: {
|
||||
rpc: "https://testnet.aurora.dev",
|
||||
key: get_env_var("ETH_KEY"),
|
||||
},
|
||||
karura: {
|
||||
rpc: "http://103.253.145.222:8545",
|
||||
key: get_env_var("ETH_KEY"),
|
||||
},
|
||||
acala: {
|
||||
rpc: "http://157.245.252.103:8545",
|
||||
key: get_env_var("ETH_KEY"),
|
||||
},
|
||||
klaytn: {
|
||||
rpc: "https://api.baobab.klaytn.net:8651",
|
||||
key: get_env_var("ETH_KEY"),
|
||||
},
|
||||
celo: {
|
||||
rpc: undefined,
|
||||
key: get_env_var("ETH_KEY"),
|
||||
},
|
||||
near: {
|
||||
rpc: undefined,
|
||||
key: undefined,
|
||||
},
|
||||
ropsten: {
|
||||
rpc: `https://ropsten.infura.io/v3/${get_env_var("INFURA_KEY")}`,
|
||||
key: get_env_var("ETH_KEY"),
|
||||
},
|
||||
};
|
||||
|
||||
const DEVNET = {
|
||||
unset: {
|
||||
rpc: undefined,
|
||||
key: undefined,
|
||||
},
|
||||
solana: {
|
||||
rpc: "http://localhost:8899",
|
||||
key: "J2D4pwDred8P9ioyPEZVLPht885AeYpifsFGUyuzVmiKQosAvmZP4EegaKFrSprBC5vVP1xTvu61vYDWsxBNsYx",
|
||||
},
|
||||
terra: {
|
||||
rpc: "http://localhost:1317",
|
||||
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",
|
||||
},
|
||||
ethereum: {
|
||||
rpc: "http://localhost:8545",
|
||||
key: "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d",
|
||||
},
|
||||
bsc: {
|
||||
rpc: "http://localhost:8546",
|
||||
key: "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d",
|
||||
},
|
||||
polygon: {
|
||||
rpc: undefined,
|
||||
key: undefined,
|
||||
},
|
||||
avalanche: {
|
||||
rpc: undefined,
|
||||
key: undefined,
|
||||
},
|
||||
oasis: {
|
||||
rpc: undefined,
|
||||
key: undefined,
|
||||
},
|
||||
algorand: {
|
||||
rpc: undefined,
|
||||
key: undefined,
|
||||
},
|
||||
fantom: {
|
||||
rpc: undefined,
|
||||
key: undefined,
|
||||
},
|
||||
aurora: {
|
||||
rpc: undefined,
|
||||
key: undefined,
|
||||
},
|
||||
karura: {
|
||||
rpc: undefined,
|
||||
key: undefined,
|
||||
},
|
||||
acala: {
|
||||
rpc: undefined,
|
||||
key: undefined,
|
||||
},
|
||||
klaytn: {
|
||||
rpc: undefined,
|
||||
key: undefined,
|
||||
},
|
||||
celo: {
|
||||
rpc: undefined,
|
||||
key: undefined,
|
||||
},
|
||||
near: {
|
||||
rpc: undefined,
|
||||
key: undefined,
|
||||
},
|
||||
ropsten: {
|
||||
rpc: undefined,
|
||||
key: undefined,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* If you get a type error here, it means that a chain you just added does not
|
||||
* have an entry in TESTNET.
|
||||
* This is implemented as an ad-hoc type assertion instead of a type annotation
|
||||
* on TESTNET so that e.g.
|
||||
*
|
||||
* ```typescript
|
||||
* TESTNET['solana'].rpc
|
||||
* ```
|
||||
* has type 'string' instead of 'string | undefined'.
|
||||
*
|
||||
* (Do not delete this declaration!)
|
||||
*/
|
||||
const isTestnetConnections: ChainConnections = TESTNET;
|
||||
|
||||
/**
|
||||
*
|
||||
* See [[isTestnetContracts]]
|
||||
*/
|
||||
const isMainnetConnections: ChainConnections = MAINNET;
|
||||
|
||||
/**
|
||||
*
|
||||
* See [[isTestnetContracts]]
|
||||
*/
|
||||
const isDevnetConnections: ChainConnections = DEVNET;
|
||||
|
||||
export const NETWORKS = { MAINNET, TESTNET, DEVNET };
|
|
@ -1,25 +1,32 @@
|
|||
{
|
||||
"name": "wormhole-client-solana",
|
||||
"name": "wormhole-client",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "wormhole-client-solana",
|
||||
"name": "wormhole-client",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@certusone/wormhole-sdk": "^0.2.0",
|
||||
"@certusone/wormhole-sdk": "^0.3.0",
|
||||
"@solana/web3.js": "^1.22.0",
|
||||
"@terra-money/terra.js": "^1.8.9",
|
||||
"axios": "^0.24.0",
|
||||
"binary-parser": "^2.0.2",
|
||||
"bn.js": "^5.2.0",
|
||||
"bs58": "^4.0.1",
|
||||
"buffer-layout": "^1.2.2",
|
||||
"dotenv": "^10.0.0",
|
||||
"ethers": "^5.4.1",
|
||||
"js-base64": "^3.6.1",
|
||||
"npm": "^7.20.0",
|
||||
"web3": "^1.5.0",
|
||||
"yargs": "^17.0.1"
|
||||
},
|
||||
"bin": {
|
||||
"worm": "build/main.js",
|
||||
"worm-fetch-governance": "worm-fetch-governance"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@truffle/hdwallet-provider": "^1.4.1",
|
||||
"@types/bn.js": "^5.1.0",
|
||||
|
@ -27,7 +34,43 @@
|
|||
"@types/yargs": "^17.0.2",
|
||||
"copy-dir": "^1.3.0",
|
||||
"ts-node": "^10.7.0",
|
||||
"typescript": "^4.3.5"
|
||||
"typescript": "^4.6"
|
||||
}
|
||||
},
|
||||
"../../sdk/js": {
|
||||
"name": "@certusone/wormhole-sdk",
|
||||
"version": "0.3.0",
|
||||
"extraneous": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@improbable-eng/grpc-web": "^0.14.0",
|
||||
"@solana/spl-token": "^0.1.8",
|
||||
"@solana/web3.js": "^1.24.0",
|
||||
"@terra-money/terra.js": "^3.0.7",
|
||||
"algosdk": "^1.15.0",
|
||||
"axios": "^0.24.0",
|
||||
"bech32": "^2.0.0",
|
||||
"js-base64": "^3.6.1",
|
||||
"protobufjs": "^6.11.2",
|
||||
"rxjs": "^7.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@improbable-eng/grpc-web-node-http-transport": "^0.15.0",
|
||||
"@openzeppelin/contracts": "^4.2.0",
|
||||
"@typechain/ethers-v5": "^7.0.1",
|
||||
"@types/jest": "^27.0.2",
|
||||
"@types/long": "^4.0.1",
|
||||
"@types/node": "^16.6.1",
|
||||
"@types/react": "^17.0.19",
|
||||
"copy-dir": "^1.3.0",
|
||||
"ethers": "^5.4.4",
|
||||
"jest": "^27.3.1",
|
||||
"prettier": "^2.3.2",
|
||||
"ts-jest": "^27.0.7",
|
||||
"tslint": "^6.1.3",
|
||||
"tslint-config-prettier": "^1.18.0",
|
||||
"typescript": "^4.3.5",
|
||||
"web3": "^1.6.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/code-frame": {
|
||||
|
@ -487,14 +530,15 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@certusone/wormhole-sdk": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@certusone/wormhole-sdk/-/wormhole-sdk-0.2.0.tgz",
|
||||
"integrity": "sha512-M5DnyPbt8Wm2gSG596yH3Fw1cXulQSzJ/4b1wVeQBrZ4g2s0ztSLgSctUGTGwR4wacK5R1IeGo9jfn29KBmdwA==",
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@certusone/wormhole-sdk/-/wormhole-sdk-0.3.0.tgz",
|
||||
"integrity": "sha512-jLZ5x8oIwBpFwVK4zYOf8ejZD7dFIkEc0P2/k7yazM+4G+CY2fKBlZnQ06OFjqbj8BvI0q/kshZcLqJx2iwObw==",
|
||||
"dependencies": {
|
||||
"@improbable-eng/grpc-web": "^0.14.0",
|
||||
"@solana/spl-token": "^0.1.8",
|
||||
"@solana/web3.js": "^1.24.0",
|
||||
"@terra-money/terra.js": "^3.0.7",
|
||||
"algosdk": "^1.15.0",
|
||||
"axios": "^0.24.0",
|
||||
"bech32": "^2.0.0",
|
||||
"js-base64": "^3.6.1",
|
||||
|
@ -503,12 +547,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@certusone/wormhole-sdk/node_modules/@terra-money/terra.js": {
|
||||
"version": "3.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@terra-money/terra.js/-/terra.js-3.0.7.tgz",
|
||||
"integrity": "sha512-moeVBWqIPZaV0HmCY127Y9H/MsuFtH1VgW0xEvDQWqu1jpKhK5CtPHMLKNje3mKSjU8A7vXZ8hlW3KobqP2poQ==",
|
||||
"version": "3.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@terra-money/terra.js/-/terra.js-3.0.11.tgz",
|
||||
"integrity": "sha512-qabXxsycWF1tEcFE3dG7FFXuIcXPlSeYgha5IYU+x4QNKiZuxT9Asi84HrCUSajQkZZ3N7ORfr+aGGE84HD+uw==",
|
||||
"dependencies": {
|
||||
"@terra-money/terra.proto": "^0.1.7",
|
||||
"axios": "^0.24.0",
|
||||
"axios": "^0.26.1",
|
||||
"bech32": "^2.0.0",
|
||||
"bip32": "^2.0.6",
|
||||
"bip39": "^3.0.3",
|
||||
|
@ -525,6 +569,14 @@
|
|||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/@certusone/wormhole-sdk/node_modules/@terra-money/terra.js/node_modules/axios": {
|
||||
"version": "0.26.1",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz",
|
||||
"integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.14.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@certusone/wormhole-sdk/node_modules/bech32": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz",
|
||||
|
@ -1949,9 +2001,9 @@
|
|||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/long": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz",
|
||||
"integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w=="
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz",
|
||||
"integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA=="
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "16.4.1",
|
||||
|
@ -2074,6 +2126,54 @@
|
|||
"url": "https://github.com/sponsors/epoberezkin"
|
||||
}
|
||||
},
|
||||
"node_modules/algo-msgpack-with-bigint": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/algo-msgpack-with-bigint/-/algo-msgpack-with-bigint-2.1.1.tgz",
|
||||
"integrity": "sha512-F1tGh056XczEaEAqu7s+hlZUDWwOBT70Eq0lfMpBP2YguSQVyxRbprLq5rELXKQOyOaixTWYhMeMQMzP0U5FoQ==",
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/algosdk": {
|
||||
"version": "1.16.0",
|
||||
"resolved": "https://registry.npmjs.org/algosdk/-/algosdk-1.16.0.tgz",
|
||||
"integrity": "sha512-oD1PEuzjJFXSx7/zwFB5N337kqykhxaPXEGgbw4IWKgjq1eRn++RAa+FH9PRwv+n9nOdzFfy83uWYwkVqliRuw==",
|
||||
"dependencies": {
|
||||
"algo-msgpack-with-bigint": "^2.1.1",
|
||||
"buffer": "^6.0.2",
|
||||
"hi-base32": "^0.5.1",
|
||||
"js-sha256": "^0.9.0",
|
||||
"js-sha3": "^0.8.0",
|
||||
"js-sha512": "^0.8.0",
|
||||
"json-bigint": "^1.0.0",
|
||||
"superagent": "^6.1.0",
|
||||
"tweetnacl": "^1.0.3",
|
||||
"url-parse": "^1.5.1"
|
||||
}
|
||||
},
|
||||
"node_modules/algosdk/node_modules/buffer": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
|
||||
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-regex": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
|
||||
|
@ -2324,6 +2424,14 @@
|
|||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/binary-parser": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/binary-parser/-/binary-parser-2.0.2.tgz",
|
||||
"integrity": "sha512-F2JeaLmExQ0vOEbS5ERzkxePKWTPqJPV6Z04/owaXMQLlW1Kt9v2gUz3SocR40JQGtrUeZu3j6prZDeuEG8Dng==",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/bindings": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
|
||||
|
@ -2854,6 +2962,11 @@
|
|||
"version": "2.20.3",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/component-emitter": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
|
||||
"integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg=="
|
||||
},
|
||||
"node_modules/compound-subject": {
|
||||
"version": "0.0.1",
|
||||
"license": "MIT"
|
||||
|
@ -4072,8 +4185,7 @@
|
|||
"node_modules/fast-safe-stringify": {
|
||||
"version": "2.0.8",
|
||||
"resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.8.tgz",
|
||||
"integrity": "sha512-lXatBjf3WPjmWD6DpIZxkeSsCOwqI0maYMpgDlx8g4U2qi4lbjA9oH/HD2a87G+KfsUmo5WbJFmqBZlPxtptag==",
|
||||
"dev": true
|
||||
"integrity": "sha512-lXatBjf3WPjmWD6DpIZxkeSsCOwqI0maYMpgDlx8g4U2qi4lbjA9oH/HD2a87G+KfsUmo5WbJFmqBZlPxtptag=="
|
||||
},
|
||||
"node_modules/fetch-ponyfill": {
|
||||
"version": "4.1.0",
|
||||
|
@ -4161,6 +4273,15 @@
|
|||
"node": ">= 0.12"
|
||||
}
|
||||
},
|
||||
"node_modules/formidable": {
|
||||
"version": "1.2.6",
|
||||
"resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.6.tgz",
|
||||
"integrity": "sha512-KcpbcpuLNOwrEjnbpMC0gS+X8ciDoZE1kkqzat4a8vrprf+s9pKNQ/QIwWfbfs4ltgmFl3MD177SNTkve3BwGQ==",
|
||||
"deprecated": "Please upgrade to latest, formidable@v2 or formidable@v3! Check these notes: https://bit.ly/2ZEqIau",
|
||||
"funding": {
|
||||
"url": "https://ko-fi.com/tunnckoCore/commissions"
|
||||
}
|
||||
},
|
||||
"node_modules/forwarded": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
|
||||
|
@ -4302,9 +4423,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/google-protobuf": {
|
||||
"version": "3.19.4",
|
||||
"resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.19.4.tgz",
|
||||
"integrity": "sha512-OIPNCxsG2lkIvf+P5FNfJ/Km95CsXOBecS9ZcAU6m2Rq3svc0Apl9nB3GMDNKfQ9asNv4KjyAqGwPQFrVle3Yg=="
|
||||
"version": "3.20.1",
|
||||
"resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.20.1.tgz",
|
||||
"integrity": "sha512-XMf1+O32FjYIV3CYu6Tuh5PNbfNEU5Xu22X+Xkdb/DUexFlCzhvv7d5Iirm4AOwn8lv4al1YvIhzGrg2j9Zfzw=="
|
||||
},
|
||||
"node_modules/got": {
|
||||
"version": "9.6.0",
|
||||
|
@ -4432,6 +4553,11 @@
|
|||
"minimalistic-assert": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/hi-base32": {
|
||||
"version": "0.5.1",
|
||||
"resolved": "https://registry.npmjs.org/hi-base32/-/hi-base32-0.5.1.tgz",
|
||||
"integrity": "sha512-EmBBpvdYh/4XxsnUybsPag6VikPYnN30td+vQk+GI3qpahVEG9+gTkG0aXVxTjBqQ5T6ijbWIu77O+C5WFWsnA=="
|
||||
},
|
||||
"node_modules/hmac-drbg": {
|
||||
"version": "1.0.1",
|
||||
"license": "MIT",
|
||||
|
@ -4870,10 +4996,20 @@
|
|||
"resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.6.1.tgz",
|
||||
"integrity": "sha512-Frdq2+tRRGLQUIQOgsIGSCd1VePCS2fsddTG5dTCqR0JHgltXWfsxnY0gIXPoMeRmdom6Oyq+UMOFg5suduOjQ=="
|
||||
},
|
||||
"node_modules/js-sha256": {
|
||||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.9.0.tgz",
|
||||
"integrity": "sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA=="
|
||||
},
|
||||
"node_modules/js-sha3": {
|
||||
"version": "0.8.0",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/js-sha512": {
|
||||
"version": "0.8.0",
|
||||
"resolved": "https://registry.npmjs.org/js-sha512/-/js-sha512-0.8.0.tgz",
|
||||
"integrity": "sha512-PWsmefG6Jkodqt+ePTvBZCSMFgN7Clckjd0O7su3I0+BW2QWUTJNzjktHsztGLhncP2h8mcF9V9Y2Ha59pAViQ=="
|
||||
},
|
||||
"node_modules/js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
|
@ -4905,6 +5041,14 @@
|
|||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/json-bigint": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz",
|
||||
"integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==",
|
||||
"dependencies": {
|
||||
"bignumber.js": "^9.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/json-buffer": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz",
|
||||
|
@ -5201,6 +5345,22 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/lru-cache/node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
},
|
||||
"node_modules/ltgt": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ltgt/-/ltgt-2.2.1.tgz",
|
||||
|
@ -8622,6 +8782,11 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/querystringify": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
|
||||
"integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ=="
|
||||
},
|
||||
"node_modules/randombytes": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
||||
|
@ -8725,6 +8890,11 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/requires-port": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
|
||||
"integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8="
|
||||
},
|
||||
"node_modules/resolve": {
|
||||
"version": "1.20.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
|
||||
|
@ -8805,9 +8975,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/rxjs": {
|
||||
"version": "7.5.4",
|
||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.4.tgz",
|
||||
"integrity": "sha512-h5M3Hk78r6wAheJF0a5YahB1yRQKCsZ4MsGdZ5O9ETbVtjPcScGfrMmoOq7EBsCRzd4BDkvDJ7ogP8Sz5tTFiQ==",
|
||||
"version": "7.5.5",
|
||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.5.tgz",
|
||||
"integrity": "sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
|
@ -9133,6 +9303,101 @@
|
|||
"npm": ">=3"
|
||||
}
|
||||
},
|
||||
"node_modules/superagent": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/superagent/-/superagent-6.1.0.tgz",
|
||||
"integrity": "sha512-OUDHEssirmplo3F+1HWKUrUjvnQuA+nZI6i/JJBdXb5eq9IyEQwPyPpqND+SSsxf6TygpBEkUjISVRN4/VOpeg==",
|
||||
"deprecated": "Please upgrade to v7.0.2+ of superagent. We have fixed numerous issues with streams, form-data, attach(), filesystem errors not bubbling up (ENOENT on attach()), and all tests are now passing. See the releases tab for more information at <https://github.com/visionmedia/superagent/releases>.",
|
||||
"dependencies": {
|
||||
"component-emitter": "^1.3.0",
|
||||
"cookiejar": "^2.1.2",
|
||||
"debug": "^4.1.1",
|
||||
"fast-safe-stringify": "^2.0.7",
|
||||
"form-data": "^3.0.0",
|
||||
"formidable": "^1.2.2",
|
||||
"methods": "^1.1.2",
|
||||
"mime": "^2.4.6",
|
||||
"qs": "^6.9.4",
|
||||
"readable-stream": "^3.6.0",
|
||||
"semver": "^7.3.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/superagent/node_modules/debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"dependencies": {
|
||||
"ms": "2.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/superagent/node_modules/form-data": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz",
|
||||
"integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==",
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"mime-types": "^2.1.12"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/superagent/node_modules/mime": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz",
|
||||
"integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==",
|
||||
"bin": {
|
||||
"mime": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/superagent/node_modules/ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
},
|
||||
"node_modules/superagent/node_modules/qs": {
|
||||
"version": "6.10.3",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz",
|
||||
"integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==",
|
||||
"dependencies": {
|
||||
"side-channel": "^1.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/superagent/node_modules/semver": {
|
||||
"version": "7.3.7",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
|
||||
"integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/superstruct": {
|
||||
"version": "0.14.2",
|
||||
"license": "MIT"
|
||||
|
@ -9424,9 +9689,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
|
||||
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
|
||||
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
|
||||
},
|
||||
"node_modules/tunnel-agent": {
|
||||
"version": "0.6.0",
|
||||
|
@ -9481,9 +9746,10 @@
|
|||
"integrity": "sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g=="
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "4.3.5",
|
||||
"version": "4.6.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.3.tgz",
|
||||
"integrity": "sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
|
@ -9535,6 +9801,15 @@
|
|||
"punycode": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/url-parse": {
|
||||
"version": "1.5.10",
|
||||
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
|
||||
"integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
|
||||
"dependencies": {
|
||||
"querystringify": "^2.1.1",
|
||||
"requires-port": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/url-parse-lax": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz",
|
||||
|
@ -10657,14 +10932,15 @@
|
|||
}
|
||||
},
|
||||
"@certusone/wormhole-sdk": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@certusone/wormhole-sdk/-/wormhole-sdk-0.2.0.tgz",
|
||||
"integrity": "sha512-M5DnyPbt8Wm2gSG596yH3Fw1cXulQSzJ/4b1wVeQBrZ4g2s0ztSLgSctUGTGwR4wacK5R1IeGo9jfn29KBmdwA==",
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@certusone/wormhole-sdk/-/wormhole-sdk-0.3.0.tgz",
|
||||
"integrity": "sha512-jLZ5x8oIwBpFwVK4zYOf8ejZD7dFIkEc0P2/k7yazM+4G+CY2fKBlZnQ06OFjqbj8BvI0q/kshZcLqJx2iwObw==",
|
||||
"requires": {
|
||||
"@improbable-eng/grpc-web": "^0.14.0",
|
||||
"@solana/spl-token": "^0.1.8",
|
||||
"@solana/web3.js": "^1.24.0",
|
||||
"@terra-money/terra.js": "^3.0.7",
|
||||
"algosdk": "^1.15.0",
|
||||
"axios": "^0.24.0",
|
||||
"bech32": "^2.0.0",
|
||||
"js-base64": "^3.6.1",
|
||||
|
@ -10673,12 +10949,12 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@terra-money/terra.js": {
|
||||
"version": "3.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@terra-money/terra.js/-/terra.js-3.0.7.tgz",
|
||||
"integrity": "sha512-moeVBWqIPZaV0HmCY127Y9H/MsuFtH1VgW0xEvDQWqu1jpKhK5CtPHMLKNje3mKSjU8A7vXZ8hlW3KobqP2poQ==",
|
||||
"version": "3.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@terra-money/terra.js/-/terra.js-3.0.11.tgz",
|
||||
"integrity": "sha512-qabXxsycWF1tEcFE3dG7FFXuIcXPlSeYgha5IYU+x4QNKiZuxT9Asi84HrCUSajQkZZ3N7ORfr+aGGE84HD+uw==",
|
||||
"requires": {
|
||||
"@terra-money/terra.proto": "^0.1.7",
|
||||
"axios": "^0.24.0",
|
||||
"axios": "^0.26.1",
|
||||
"bech32": "^2.0.0",
|
||||
"bip32": "^2.0.6",
|
||||
"bip39": "^3.0.3",
|
||||
|
@ -10690,6 +10966,16 @@
|
|||
"tmp": "^0.2.1",
|
||||
"utf-8-validate": "^5.0.5",
|
||||
"ws": "^7.5.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": {
|
||||
"version": "0.26.1",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz",
|
||||
"integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==",
|
||||
"requires": {
|
||||
"follow-redirects": "^1.14.8"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"bech32": {
|
||||
|
@ -11717,9 +12003,9 @@
|
|||
"version": "4.14.171"
|
||||
},
|
||||
"@types/long": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz",
|
||||
"integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w=="
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz",
|
||||
"integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA=="
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "16.4.1"
|
||||
|
@ -11813,6 +12099,39 @@
|
|||
"uri-js": "^4.2.2"
|
||||
}
|
||||
},
|
||||
"algo-msgpack-with-bigint": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/algo-msgpack-with-bigint/-/algo-msgpack-with-bigint-2.1.1.tgz",
|
||||
"integrity": "sha512-F1tGh056XczEaEAqu7s+hlZUDWwOBT70Eq0lfMpBP2YguSQVyxRbprLq5rELXKQOyOaixTWYhMeMQMzP0U5FoQ=="
|
||||
},
|
||||
"algosdk": {
|
||||
"version": "1.16.0",
|
||||
"resolved": "https://registry.npmjs.org/algosdk/-/algosdk-1.16.0.tgz",
|
||||
"integrity": "sha512-oD1PEuzjJFXSx7/zwFB5N337kqykhxaPXEGgbw4IWKgjq1eRn++RAa+FH9PRwv+n9nOdzFfy83uWYwkVqliRuw==",
|
||||
"requires": {
|
||||
"algo-msgpack-with-bigint": "^2.1.1",
|
||||
"buffer": "^6.0.2",
|
||||
"hi-base32": "^0.5.1",
|
||||
"js-sha256": "^0.9.0",
|
||||
"js-sha3": "^0.8.0",
|
||||
"js-sha512": "^0.8.0",
|
||||
"json-bigint": "^1.0.0",
|
||||
"superagent": "^6.1.0",
|
||||
"tweetnacl": "^1.0.3",
|
||||
"url-parse": "^1.5.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"buffer": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
|
||||
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
|
||||
"requires": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.2.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ansi-regex": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
|
||||
|
@ -12014,6 +12333,11 @@
|
|||
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz",
|
||||
"integrity": "sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA=="
|
||||
},
|
||||
"binary-parser": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/binary-parser/-/binary-parser-2.0.2.tgz",
|
||||
"integrity": "sha512-F2JeaLmExQ0vOEbS5ERzkxePKWTPqJPV6Z04/owaXMQLlW1Kt9v2gUz3SocR40JQGtrUeZu3j6prZDeuEG8Dng=="
|
||||
},
|
||||
"bindings": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
|
||||
|
@ -12450,6 +12774,11 @@
|
|||
"commander": {
|
||||
"version": "2.20.3"
|
||||
},
|
||||
"component-emitter": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
|
||||
"integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg=="
|
||||
},
|
||||
"compound-subject": {
|
||||
"version": "0.0.1"
|
||||
},
|
||||
|
@ -13565,8 +13894,7 @@
|
|||
"fast-safe-stringify": {
|
||||
"version": "2.0.8",
|
||||
"resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.8.tgz",
|
||||
"integrity": "sha512-lXatBjf3WPjmWD6DpIZxkeSsCOwqI0maYMpgDlx8g4U2qi4lbjA9oH/HD2a87G+KfsUmo5WbJFmqBZlPxtptag==",
|
||||
"dev": true
|
||||
"integrity": "sha512-lXatBjf3WPjmWD6DpIZxkeSsCOwqI0maYMpgDlx8g4U2qi4lbjA9oH/HD2a87G+KfsUmo5WbJFmqBZlPxtptag=="
|
||||
},
|
||||
"fetch-ponyfill": {
|
||||
"version": "4.1.0",
|
||||
|
@ -13633,6 +13961,11 @@
|
|||
"mime-types": "^2.1.12"
|
||||
}
|
||||
},
|
||||
"formidable": {
|
||||
"version": "1.2.6",
|
||||
"resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.6.tgz",
|
||||
"integrity": "sha512-KcpbcpuLNOwrEjnbpMC0gS+X8ciDoZE1kkqzat4a8vrprf+s9pKNQ/QIwWfbfs4ltgmFl3MD177SNTkve3BwGQ=="
|
||||
},
|
||||
"forwarded": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
|
||||
|
@ -13747,9 +14080,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"google-protobuf": {
|
||||
"version": "3.19.4",
|
||||
"resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.19.4.tgz",
|
||||
"integrity": "sha512-OIPNCxsG2lkIvf+P5FNfJ/Km95CsXOBecS9ZcAU6m2Rq3svc0Apl9nB3GMDNKfQ9asNv4KjyAqGwPQFrVle3Yg=="
|
||||
"version": "3.20.1",
|
||||
"resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.20.1.tgz",
|
||||
"integrity": "sha512-XMf1+O32FjYIV3CYu6Tuh5PNbfNEU5Xu22X+Xkdb/DUexFlCzhvv7d5Iirm4AOwn8lv4al1YvIhzGrg2j9Zfzw=="
|
||||
},
|
||||
"got": {
|
||||
"version": "9.6.0",
|
||||
|
@ -13842,6 +14175,11 @@
|
|||
"minimalistic-assert": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"hi-base32": {
|
||||
"version": "0.5.1",
|
||||
"resolved": "https://registry.npmjs.org/hi-base32/-/hi-base32-0.5.1.tgz",
|
||||
"integrity": "sha512-EmBBpvdYh/4XxsnUybsPag6VikPYnN30td+vQk+GI3qpahVEG9+gTkG0aXVxTjBqQ5T6ijbWIu77O+C5WFWsnA=="
|
||||
},
|
||||
"hmac-drbg": {
|
||||
"version": "1.0.1",
|
||||
"requires": {
|
||||
|
@ -14137,9 +14475,19 @@
|
|||
"resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.6.1.tgz",
|
||||
"integrity": "sha512-Frdq2+tRRGLQUIQOgsIGSCd1VePCS2fsddTG5dTCqR0JHgltXWfsxnY0gIXPoMeRmdom6Oyq+UMOFg5suduOjQ=="
|
||||
},
|
||||
"js-sha256": {
|
||||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.9.0.tgz",
|
||||
"integrity": "sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA=="
|
||||
},
|
||||
"js-sha3": {
|
||||
"version": "0.8.0"
|
||||
},
|
||||
"js-sha512": {
|
||||
"version": "0.8.0",
|
||||
"resolved": "https://registry.npmjs.org/js-sha512/-/js-sha512-0.8.0.tgz",
|
||||
"integrity": "sha512-PWsmefG6Jkodqt+ePTvBZCSMFgN7Clckjd0O7su3I0+BW2QWUTJNzjktHsztGLhncP2h8mcF9V9Y2Ha59pAViQ=="
|
||||
},
|
||||
"js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
|
@ -14162,6 +14510,14 @@
|
|||
"integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
|
||||
"dev": true
|
||||
},
|
||||
"json-bigint": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz",
|
||||
"integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==",
|
||||
"requires": {
|
||||
"bignumber.js": "^9.0.0"
|
||||
}
|
||||
},
|
||||
"json-buffer": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz",
|
||||
|
@ -14425,6 +14781,21 @@
|
|||
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz",
|
||||
"integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA=="
|
||||
},
|
||||
"lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"requires": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"ltgt": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ltgt/-/ltgt-2.2.1.tgz",
|
||||
|
@ -16881,6 +17252,11 @@
|
|||
"strict-uri-encode": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"querystringify": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
|
||||
"integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ=="
|
||||
},
|
||||
"randombytes": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
||||
|
@ -16966,6 +17342,11 @@
|
|||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||
"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I="
|
||||
},
|
||||
"requires-port": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
|
||||
"integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8="
|
||||
},
|
||||
"resolve": {
|
||||
"version": "1.20.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
|
||||
|
@ -17033,9 +17414,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"rxjs": {
|
||||
"version": "7.5.4",
|
||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.4.tgz",
|
||||
"integrity": "sha512-h5M3Hk78r6wAheJF0a5YahB1yRQKCsZ4MsGdZ5O9ETbVtjPcScGfrMmoOq7EBsCRzd4BDkvDJ7ogP8Sz5tTFiQ==",
|
||||
"version": "7.5.5",
|
||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.5.tgz",
|
||||
"integrity": "sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw==",
|
||||
"requires": {
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
|
@ -17273,6 +17654,70 @@
|
|||
"is-hex-prefixed": "1.0.0"
|
||||
}
|
||||
},
|
||||
"superagent": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/superagent/-/superagent-6.1.0.tgz",
|
||||
"integrity": "sha512-OUDHEssirmplo3F+1HWKUrUjvnQuA+nZI6i/JJBdXb5eq9IyEQwPyPpqND+SSsxf6TygpBEkUjISVRN4/VOpeg==",
|
||||
"requires": {
|
||||
"component-emitter": "^1.3.0",
|
||||
"cookiejar": "^2.1.2",
|
||||
"debug": "^4.1.1",
|
||||
"fast-safe-stringify": "^2.0.7",
|
||||
"form-data": "^3.0.0",
|
||||
"formidable": "^1.2.2",
|
||||
"methods": "^1.1.2",
|
||||
"mime": "^2.4.6",
|
||||
"qs": "^6.9.4",
|
||||
"readable-stream": "^3.6.0",
|
||||
"semver": "^7.3.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
},
|
||||
"form-data": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz",
|
||||
"integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==",
|
||||
"requires": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"mime-types": "^2.1.12"
|
||||
}
|
||||
},
|
||||
"mime": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz",
|
||||
"integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg=="
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
},
|
||||
"qs": {
|
||||
"version": "6.10.3",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz",
|
||||
"integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==",
|
||||
"requires": {
|
||||
"side-channel": "^1.0.4"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "7.3.7",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
|
||||
"integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
|
||||
"requires": {
|
||||
"lru-cache": "^6.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"superstruct": {
|
||||
"version": "0.14.2"
|
||||
},
|
||||
|
@ -17482,9 +17927,9 @@
|
|||
}
|
||||
},
|
||||
"tslib": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
|
||||
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
|
||||
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
|
||||
},
|
||||
"tunnel-agent": {
|
||||
"version": "0.6.0",
|
||||
|
@ -17528,7 +17973,9 @@
|
|||
"integrity": "sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g=="
|
||||
},
|
||||
"typescript": {
|
||||
"version": "4.3.5",
|
||||
"version": "4.6.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.3.tgz",
|
||||
"integrity": "sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==",
|
||||
"dev": true
|
||||
},
|
||||
"ultron": {
|
||||
|
@ -17565,6 +18012,15 @@
|
|||
"punycode": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"url-parse": {
|
||||
"version": "1.5.10",
|
||||
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
|
||||
"integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
|
||||
"requires": {
|
||||
"querystringify": "^2.1.1",
|
||||
"requires-port": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"url-parse-lax": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz",
|
|
@ -1,24 +1,30 @@
|
|||
{
|
||||
"name": "wormhole-client-solana",
|
||||
"name": "wormhole-client",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@certusone/wormhole-sdk": "^0.2.0",
|
||||
"@certusone/wormhole-sdk": "^0.3.0",
|
||||
"@solana/web3.js": "^1.22.0",
|
||||
"@terra-money/terra.js": "^1.8.9",
|
||||
"axios": "^0.24.0",
|
||||
"binary-parser": "^2.0.2",
|
||||
"bn.js": "^5.2.0",
|
||||
"bs58": "^4.0.1",
|
||||
"buffer-layout": "^1.2.2",
|
||||
"dotenv": "^10.0.0",
|
||||
"ethers": "^5.4.1",
|
||||
"js-base64": "^3.6.1",
|
||||
"npm": "^7.20.0",
|
||||
"web3": "^1.5.0",
|
||||
"yargs": "^17.0.1"
|
||||
},
|
||||
"bin": {
|
||||
"worm": "./build/main.js",
|
||||
"worm-fetch-governance": "./worm-fetch-governance"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "tsc && node main.js",
|
||||
"start": "ts-node main.ts",
|
||||
"build": "tsc",
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"main": "ts-node main.ts"
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@truffle/hdwallet-provider": "^1.4.1",
|
||||
|
@ -27,6 +33,6 @@
|
|||
"@types/yargs": "^17.0.2",
|
||||
"copy-dir": "^1.3.0",
|
||||
"ts-node": "^10.7.0",
|
||||
"typescript": "^4.3.5"
|
||||
"typescript": "^4.6"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
import * as web3s from '@solana/web3.js'
|
||||
import { NETWORKS } from "./networks";
|
||||
import { impossible, Payload, VAA } from "./vaa";
|
||||
import base58 from "bs58";
|
||||
import { importCoreWasm, importNftWasm, importTokenWasm, ixFromRust } from "@certusone/wormhole-sdk";
|
||||
import { CONTRACTS } from "@certusone/wormhole-sdk"
|
||||
import { postVaaSolanaWithRetry } from "@certusone/wormhole-sdk"
|
||||
|
||||
export async function execute_governance_solana(
|
||||
v: VAA<Payload>,
|
||||
vaa: Buffer,
|
||||
network: "MAINNET" | "TESTNET" | "DEVNET"
|
||||
) {
|
||||
let ix: web3s.TransactionInstruction
|
||||
let connection = setupConnection(NETWORKS[network].solana.rpc)
|
||||
let bridge_id = new web3s.PublicKey(CONTRACTS[network].solana.core)
|
||||
let token_bridge_id = new web3s.PublicKey(CONTRACTS[network].solana.token_bridge)
|
||||
let nft_bridge_id = new web3s.PublicKey(CONTRACTS[network].solana.nft_bridge)
|
||||
|
||||
let from = web3s.Keypair.fromSecretKey(base58.decode(NETWORKS[network].solana.key))
|
||||
|
||||
switch (v.payload.module) {
|
||||
case "Core":
|
||||
const bridge = await importCoreWasm()
|
||||
switch (v.payload.type) {
|
||||
case "GuardianSetUpgrade":
|
||||
console.log("Submitting new guardian set")
|
||||
ix = bridge.update_guardian_set_ix(bridge_id.toString(), from.publicKey.toString(), vaa);
|
||||
break
|
||||
case "ContractUpgrade":
|
||||
console.log("Upgrading core contract")
|
||||
ix = bridge.upgrade_contract_ix(bridge_id.toString(), from.publicKey.toString(), from.publicKey.toString(), vaa);
|
||||
break
|
||||
default:
|
||||
ix = impossible(v.payload)
|
||||
}
|
||||
break
|
||||
case "NFTBridge":
|
||||
const nft_bridge = await importNftWasm()
|
||||
switch (v.payload.type) {
|
||||
case "ContractUpgrade":
|
||||
console.log("Upgrading contract")
|
||||
ix = nft_bridge.upgrade_contract_ix(nft_bridge_id.toString(), bridge_id.toString(), from.publicKey.toString(), from.publicKey.toString(), vaa);
|
||||
break
|
||||
case "RegisterChain":
|
||||
console.log("Registering chain")
|
||||
ix = nft_bridge.register_chain_ix(nft_bridge_id.toString(), bridge_id.toString(), from.publicKey.toString(), vaa);
|
||||
break
|
||||
default:
|
||||
ix = impossible(v.payload)
|
||||
|
||||
}
|
||||
break
|
||||
case "TokenBridge":
|
||||
const token_bridge = await importTokenWasm()
|
||||
switch (v.payload.type) {
|
||||
case "ContractUpgrade":
|
||||
console.log("Upgrading contract")
|
||||
ix = token_bridge.upgrade_contract_ix(token_bridge_id.toString(), bridge_id.toString(), from.publicKey.toString(), from.publicKey.toString(), vaa)
|
||||
break
|
||||
case "RegisterChain":
|
||||
console.log("Registering chain")
|
||||
ix = token_bridge.register_chain_ix(token_bridge_id.toString(), bridge_id.toString(), from.publicKey.toString(), vaa)
|
||||
break
|
||||
default:
|
||||
ix = impossible(v.payload)
|
||||
|
||||
}
|
||||
break
|
||||
default:
|
||||
ix = impossible(v.payload)
|
||||
}
|
||||
|
||||
// First upload the VAA
|
||||
await postVaaSolanaWithRetry(connection,
|
||||
async (tx) => {
|
||||
tx.partialSign(from)
|
||||
return tx
|
||||
},
|
||||
bridge_id.toString(), from.publicKey.toString(), vaa, 5)
|
||||
|
||||
// Then do the actual thing
|
||||
let transaction = new web3s.Transaction().add(ixFromRust(ix))
|
||||
|
||||
let signature = await web3s.sendAndConfirmTransaction(
|
||||
connection,
|
||||
transaction,
|
||||
[from],
|
||||
{
|
||||
skipPreflight: true
|
||||
}
|
||||
)
|
||||
console.log('SIGNATURE', signature)
|
||||
}
|
||||
|
||||
function setupConnection(rpc: string): web3s.Connection {
|
||||
return new web3s.Connection(
|
||||
rpc,
|
||||
'confirmed',
|
||||
)
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
import { LCDClient, MnemonicKey, MsgExecuteContract } from "@terra-money/terra.js";
|
||||
import { fromUint8Array } from "js-base64";
|
||||
import { impossible, Payload } from "./vaa";
|
||||
import { NETWORKS } from "./networks"
|
||||
import { CONTRACTS } from "@certusone/wormhole-sdk"
|
||||
|
||||
export async function execute_governance_terra(
|
||||
payload: Payload,
|
||||
vaa: Buffer,
|
||||
network: "MAINNET" | "TESTNET" | "DEVNET"
|
||||
) {
|
||||
|
||||
let n = NETWORKS[network]['terra']
|
||||
let contracts = CONTRACTS[network]['terra']
|
||||
|
||||
const terra = new LCDClient({
|
||||
URL: n.rpc,
|
||||
chainID: n.chain_id,
|
||||
})
|
||||
|
||||
const wallet = terra.wallet(new MnemonicKey({
|
||||
mnemonic: n.key
|
||||
}))
|
||||
|
||||
let target_contract: string
|
||||
let execute_msg: object
|
||||
|
||||
switch (payload.module) {
|
||||
case "Core":
|
||||
target_contract = contracts.core
|
||||
// sigh...
|
||||
execute_msg = {
|
||||
submit_v_a_a: {
|
||||
vaa: fromUint8Array(vaa)
|
||||
},
|
||||
}
|
||||
switch (payload.type) {
|
||||
case "GuardianSetUpgrade":
|
||||
console.log("Submitting new guardian set")
|
||||
break
|
||||
case "ContractUpgrade":
|
||||
console.log("Upgrading core contract")
|
||||
break
|
||||
default:
|
||||
impossible(payload)
|
||||
}
|
||||
break
|
||||
case "NFTBridge":
|
||||
if (contracts.nft_bridge === undefined) {
|
||||
// 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
|
||||
// skipped once 'contracts.nft_bridge' is defined
|
||||
throw new Error("NFT bridge not supported yet for terra")
|
||||
}
|
||||
target_contract = contracts.nft_bridge
|
||||
execute_msg = {
|
||||
submit_vaa: {
|
||||
data: fromUint8Array(vaa)
|
||||
},
|
||||
}
|
||||
switch (payload.type) {
|
||||
case "ContractUpgrade":
|
||||
console.log("Upgrading contract")
|
||||
break
|
||||
case "RegisterChain":
|
||||
console.log("Registering chain")
|
||||
break
|
||||
default:
|
||||
impossible(payload)
|
||||
|
||||
}
|
||||
break
|
||||
case "TokenBridge":
|
||||
target_contract = contracts.token_bridge
|
||||
execute_msg = {
|
||||
submit_vaa: {
|
||||
data: fromUint8Array(vaa)
|
||||
},
|
||||
}
|
||||
switch (payload.type) {
|
||||
case "ContractUpgrade":
|
||||
console.log("Upgrading contract")
|
||||
break
|
||||
case "RegisterChain":
|
||||
console.log("Registering chain")
|
||||
break
|
||||
default:
|
||||
impossible(payload)
|
||||
execute_msg = impossible(payload)
|
||||
|
||||
}
|
||||
break
|
||||
default:
|
||||
target_contract = impossible(payload)
|
||||
execute_msg = impossible(payload)
|
||||
}
|
||||
|
||||
const transaction = new MsgExecuteContract(
|
||||
wallet.key.accAddress,
|
||||
target_contract,
|
||||
execute_msg,
|
||||
{ uluna: 1000 }
|
||||
)
|
||||
|
||||
wallet
|
||||
.createAndSignTx({
|
||||
msgs: [transaction],
|
||||
memo: '',
|
||||
})
|
||||
.then(tx => terra.tx.broadcast(tx))
|
||||
.then(result => {
|
||||
console.log(result)
|
||||
console.log(`TX hash: ${result.txhash}`)
|
||||
})
|
||||
}
|
|
@ -3,8 +3,8 @@
|
|||
/* Visit https://aka.ms/tsconfig.json to read more about this file */
|
||||
|
||||
/* Basic Options */
|
||||
// "incremental": true, /* Enable incremental compilation */
|
||||
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */
|
||||
"incremental": true, /* Enable incremental compilation */
|
||||
"target": "es2019", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */
|
||||
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
|
||||
// "lib": [], /* Specify library files to be included in the compilation. */
|
||||
// "allowJs": true, /* Allow javascript files to be compiled. */
|
||||
|
@ -14,19 +14,19 @@
|
|||
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
||||
// "sourceMap": true, /* Generates corresponding '.map' file. */
|
||||
// "outFile": "./", /* Concatenate and emit output to single file. */
|
||||
// "outDir": "./", /* Redirect output structure to the directory. */
|
||||
"outDir": "./build", /* Redirect output structure to the directory. */
|
||||
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
||||
// "composite": true, /* Enable project compilation */
|
||||
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
|
||||
// "removeComments": true, /* Do not emit comments to output. */
|
||||
// "noEmit": true, /* Do not emit outputs. */
|
||||
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
|
||||
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
|
||||
"downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
|
||||
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
|
||||
|
||||
/* Strict Type-Checking Options */
|
||||
"strict": true, /* Enable all strict type-checking options. */
|
||||
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
|
||||
"strict": false, /* Enable all strict type-checking options. */
|
||||
"noImplicitAny": false, /* Raise error on expressions and declarations with an implied 'any' type. */
|
||||
// "strictNullChecks": true, /* Enable strict null checks. */
|
||||
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
|
||||
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"indentSize": 2,
|
||||
"tabSize": 2,
|
||||
"insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": false,
|
||||
"placeOpenBraceOnNewLineForFunctions": false,
|
||||
"placeOpenBraceOnNewLineForControlBlocks": false
|
||||
}
|
|
@ -0,0 +1,450 @@
|
|||
import { Parser } from "binary-parser"
|
||||
import { ethers } from "ethers"
|
||||
import { solidityKeccak256 } from "ethers/lib/utils"
|
||||
import * as elliptic from "elliptic"
|
||||
|
||||
export interface Signature {
|
||||
guardianSetIndex: number
|
||||
signature: string
|
||||
}
|
||||
|
||||
export interface VAA<T> {
|
||||
version: number
|
||||
guardianSetIndex: number
|
||||
signatures: Signature[]
|
||||
timestamp: number
|
||||
nonce: number
|
||||
emitterChain: number
|
||||
emitterAddress: string
|
||||
sequence: bigint
|
||||
consistencyLevel: number
|
||||
payload: T
|
||||
}
|
||||
|
||||
class P<T> {
|
||||
private parser: Parser
|
||||
constructor(parser: Parser) {
|
||||
this.parser = parser
|
||||
}
|
||||
|
||||
// Try to parse a buffer with a parser, and return null if it failed due to an
|
||||
// assertion error.
|
||||
parse(buffer: Buffer): T | null {
|
||||
try {
|
||||
let result = this.parser.parse(buffer)
|
||||
delete result['end']
|
||||
return result
|
||||
} catch (e: any) {
|
||||
if (e.message?.includes("Assertion error")) {
|
||||
return null
|
||||
} else {
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
or<U>(other: P<U>): P<T | U> {
|
||||
let p = new P<T | U>(other.parser);
|
||||
p.parse = (buffer: Buffer): T | U | null => {
|
||||
return this.parse(buffer) ?? other.parse(buffer)
|
||||
}
|
||||
return p
|
||||
}
|
||||
}
|
||||
|
||||
// All the different types of payloads
|
||||
export type Payload =
|
||||
GuardianSetUpgrade
|
||||
| CoreContractUpgrade
|
||||
| PortalContractUpgrade<"TokenBridge">
|
||||
| PortalContractUpgrade<"NFTBridge">
|
||||
| PortalRegisterChain<"TokenBridge">
|
||||
| PortalRegisterChain<"NFTBridge">
|
||||
// TODO: add other types of payloads
|
||||
|
||||
export function parse(buffer: Buffer): VAA<Payload | null> {
|
||||
const vaa = parseEnvelope(buffer)
|
||||
const parser = guardianSetUpgradeParser
|
||||
.or(coreContractUpgradeParser)
|
||||
.or(portalContractUpgradeParser("TokenBridge"))
|
||||
.or(portalContractUpgradeParser("NFTBridge"))
|
||||
.or(portalRegisterChainParser("TokenBridge"))
|
||||
.or(portalRegisterChainParser("NFTBridge"))
|
||||
const payload = parser.parse(vaa.payload)
|
||||
var myVAA = { ...vaa, payload }
|
||||
|
||||
return myVAA
|
||||
}
|
||||
|
||||
export function hasPayload(vaa: VAA<Payload | null>): vaa is VAA<Payload> {
|
||||
return vaa.payload !== null
|
||||
}
|
||||
|
||||
// Parse the VAA envelope without looking into the payload.
|
||||
// If you want to parse the payload as well, use 'parse'.
|
||||
export function parseEnvelope(buffer: Buffer): VAA<Buffer> {
|
||||
var vaa = vaaParser.parse(buffer)
|
||||
delete vaa['end']
|
||||
delete vaa['signatureCount']
|
||||
vaa.payload = Buffer.from(vaa.payload)
|
||||
return vaa
|
||||
}
|
||||
|
||||
// Parse a signature
|
||||
const signatureParser = new Parser()
|
||||
.endianess("big")
|
||||
.uint8("guardianSetIndex")
|
||||
.array("signature", {
|
||||
type: "uint8",
|
||||
lengthInBytes: 65,
|
||||
formatter: arr => Buffer.from(arr).toString("hex")
|
||||
})
|
||||
|
||||
function serialiseSignature(sig: Signature): string {
|
||||
const body = [
|
||||
encode("uint8", sig.guardianSetIndex),
|
||||
sig.signature
|
||||
]
|
||||
return body.join("")
|
||||
}
|
||||
|
||||
// Parse a vaa envelope. The payload is returned as a byte array.
|
||||
const vaaParser = new Parser()
|
||||
.endianess("big")
|
||||
.uint8("version")
|
||||
.uint32("guardianSetIndex")
|
||||
.uint8("signatureCount")
|
||||
.array("signatures", {
|
||||
type: signatureParser,
|
||||
length: "signatureCount"
|
||||
})
|
||||
.uint32("timestamp")
|
||||
.uint32("nonce")
|
||||
.uint16("emitterChain")
|
||||
.array("emitterAddress", {
|
||||
type: "uint8",
|
||||
lengthInBytes: 32,
|
||||
formatter: arr => Buffer.from(arr).toString("hex")
|
||||
})
|
||||
.uint64("sequence")
|
||||
.uint8("consistencyLevel")
|
||||
.array("payload", {
|
||||
type: "uint8",
|
||||
readUntil: "eof"
|
||||
})
|
||||
.string("end", {
|
||||
greedy: true,
|
||||
assert: str => str === ""
|
||||
})
|
||||
|
||||
export function serialiseVAA(vaa: VAA<Payload>) {
|
||||
const body = [
|
||||
encode("uint8", vaa.version),
|
||||
encode("uint32", vaa.guardianSetIndex),
|
||||
encode("uint8", vaa.signatures.length),
|
||||
...(vaa.signatures.map((sig) => serialiseSignature(sig))),
|
||||
vaaBody(vaa)
|
||||
]
|
||||
return body.join("")
|
||||
}
|
||||
|
||||
function vaaBody(vaa: VAA<Payload>) {
|
||||
let payload = vaa.payload
|
||||
let payload_str: string
|
||||
switch (payload.module) {
|
||||
case "Core":
|
||||
switch (payload.type) {
|
||||
case "GuardianSetUpgrade":
|
||||
payload_str = serialiseGuardianSetUpgrade(payload)
|
||||
break
|
||||
case "ContractUpgrade":
|
||||
payload_str = serialiseCoreContractUpgrade(payload)
|
||||
break
|
||||
}
|
||||
break
|
||||
case "NFTBridge":
|
||||
case "TokenBridge":
|
||||
switch (payload.type) {
|
||||
case "ContractUpgrade":
|
||||
payload_str = serialisePortalContractUpgrade(payload)
|
||||
break
|
||||
case "RegisterChain":
|
||||
payload_str = serialisePortalRegisterChain(payload)
|
||||
break
|
||||
}
|
||||
break
|
||||
}
|
||||
const body = [
|
||||
encode("uint32", vaa.timestamp),
|
||||
encode("uint32", vaa.nonce),
|
||||
encode("uint16", vaa.emitterChain),
|
||||
encode("bytes32", Buffer.from(vaa.emitterAddress, "hex")),
|
||||
encode("uint64", vaa.sequence),
|
||||
encode("uint8", vaa.consistencyLevel),
|
||||
payload_str
|
||||
]
|
||||
return body.join("")
|
||||
}
|
||||
|
||||
export function sign(signers: string[], vaa: VAA<Payload>): Signature[] {
|
||||
const body = vaaBody(vaa)
|
||||
const hash = solidityKeccak256(["bytes"], [solidityKeccak256(["bytes"], ["0x" + body])])
|
||||
const ec = new elliptic.ec("secp256k1")
|
||||
|
||||
return signers.map((signer, i) => {
|
||||
const key = ec.keyFromPrivate(signer)
|
||||
const signature = key.sign(Buffer.from(hash.substr(2), "hex"), { canonical: true })
|
||||
const packed = [
|
||||
signature.r.toString("hex").padStart(64, "0"),
|
||||
signature.s.toString("hex").padStart(64, "0"),
|
||||
encode("uint8", signature.recoveryParam)
|
||||
].join("")
|
||||
return {
|
||||
guardianSetIndex: i,
|
||||
signature: packed
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Parse an address of given length, and render it as hex
|
||||
const addressParser = (length: number) => new Parser()
|
||||
.endianess("big")
|
||||
.array("address", {
|
||||
type: "uint8",
|
||||
lengthInBytes: length,
|
||||
formatter: (arr) => Buffer.from(arr).toString("hex")
|
||||
})
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Guardian set upgrade
|
||||
|
||||
export interface GuardianSetUpgrade {
|
||||
module: "Core"
|
||||
type: "GuardianSetUpgrade"
|
||||
chain: number
|
||||
newGuardianSetIndex: number
|
||||
newGuardianSetLength: number
|
||||
newGuardianSet: string[]
|
||||
}
|
||||
|
||||
// Parse a guardian set upgrade payload
|
||||
const guardianSetUpgradeParser: P<GuardianSetUpgrade> = new P(new Parser()
|
||||
.endianess("big")
|
||||
.string("module", {
|
||||
length: 32,
|
||||
encoding: "hex",
|
||||
assert: Buffer.from("Core").toString("hex").padStart(64, "0"),
|
||||
formatter: (_str) => "Core"
|
||||
})
|
||||
.uint8("type", {
|
||||
assert: 2,
|
||||
formatter: (_action) => "GuardianSetUpgrade"
|
||||
})
|
||||
.uint16("chain")
|
||||
.uint32("newGuardianSetIndex")
|
||||
.uint8("newGuardianSetLength")
|
||||
.array("newGuardianSet", {
|
||||
type: addressParser(20),
|
||||
length: "newGuardianSetLength",
|
||||
formatter: (arr: [{ address: string }]) => arr.map((addr) => addr.address)
|
||||
})
|
||||
.string("end", {
|
||||
greedy: true,
|
||||
assert: str => str === ""
|
||||
}))
|
||||
|
||||
function serialiseGuardianSetUpgrade(payload: GuardianSetUpgrade): string {
|
||||
const body = [
|
||||
encode("bytes32", Buffer.from(Buffer.from(payload.module).toString("hex").padStart(64, "0"), "hex")),
|
||||
encode("uint8", 2),
|
||||
encode("uint16", payload.chain),
|
||||
encode("uint32", payload.newGuardianSetIndex),
|
||||
encode("uint8", payload.newGuardianSet.length),
|
||||
...payload.newGuardianSet
|
||||
]
|
||||
return body.join("")
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Contract upgrades
|
||||
|
||||
export interface CoreContractUpgrade {
|
||||
module: "Core"
|
||||
type: "ContractUpgrade"
|
||||
chain: number
|
||||
address: Uint8Array
|
||||
}
|
||||
|
||||
// Parse a core contract upgrade payload
|
||||
const coreContractUpgradeParser: P<CoreContractUpgrade> =
|
||||
new P(new Parser()
|
||||
.endianess("big")
|
||||
.string("module", {
|
||||
length: 32,
|
||||
encoding: "hex",
|
||||
assert: Buffer.from("Core").toString("hex").padStart(64, "0"),
|
||||
formatter: (_str) => module
|
||||
})
|
||||
.uint8("type", {
|
||||
assert: 1,
|
||||
formatter: (_action) => "ContractUpgrade"
|
||||
})
|
||||
.uint16("chain")
|
||||
.array("address", {
|
||||
type: "uint8",
|
||||
lengthInBytes: 32,
|
||||
// formatter: (arr) => Buffer.from(arr).toString("hex")
|
||||
})
|
||||
.string("end", {
|
||||
greedy: true,
|
||||
assert: str => str === ""
|
||||
}))
|
||||
|
||||
function serialiseCoreContractUpgrade(payload: CoreContractUpgrade): string {
|
||||
const body = [
|
||||
encode("bytes32", encodeString(payload.module)),
|
||||
encode("uint8", 1),
|
||||
encode("uint16", payload.chain),
|
||||
encode("bytes32", payload.address)
|
||||
]
|
||||
return body.join("")
|
||||
}
|
||||
|
||||
export interface PortalContractUpgrade<Module extends "NFTBridge" | "TokenBridge"> {
|
||||
module: Module
|
||||
type: "ContractUpgrade"
|
||||
chain: number
|
||||
address: Uint8Array
|
||||
}
|
||||
|
||||
// Parse a portal contract upgrade payload
|
||||
function portalContractUpgradeParser<Module extends "NFTBridge" | "TokenBridge">(module: Module): P<PortalContractUpgrade<Module>> {
|
||||
return new P(new Parser()
|
||||
.endianess("big")
|
||||
.string("module", {
|
||||
length: 32,
|
||||
encoding: "hex",
|
||||
assert: Buffer.from(module).toString("hex").padStart(64, "0"),
|
||||
formatter: (_str: string) => module
|
||||
})
|
||||
.uint8("type", {
|
||||
assert: 2,
|
||||
formatter: (_action: number) => "ContractUpgrade"
|
||||
})
|
||||
.uint16("chain")
|
||||
.array("address", {
|
||||
type: "uint8",
|
||||
lengthInBytes: 32,
|
||||
// formatter: (arr) => Buffer.from(arr).toString("hex")
|
||||
})
|
||||
.string("end", {
|
||||
greedy: true,
|
||||
assert: str => str === ""
|
||||
}))
|
||||
}
|
||||
|
||||
function serialisePortalContractUpgrade<Module extends "NFTBridge" | "TokenBridge">(payload: PortalContractUpgrade<Module>): string {
|
||||
const body = [
|
||||
encode("bytes32", encodeString(payload.module)),
|
||||
encode("uint8", 2),
|
||||
encode("uint16", payload.chain),
|
||||
encode("bytes32", payload.address)
|
||||
]
|
||||
return body.join("")
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Registrations
|
||||
|
||||
export interface PortalRegisterChain<Module extends "NFTBridge" | "TokenBridge"> {
|
||||
module: Module
|
||||
type: "RegisterChain"
|
||||
chain: number
|
||||
emitterChain: number
|
||||
emitterAddress: Uint8Array
|
||||
}
|
||||
|
||||
// Parse a portal chain registration payload
|
||||
function portalRegisterChainParser<Module extends "NFTBridge" | "TokenBridge">(module: Module): P<PortalRegisterChain<Module>> {
|
||||
return new P(new Parser()
|
||||
.endianess("big")
|
||||
.string("module", {
|
||||
length: 32,
|
||||
encoding: "hex",
|
||||
assert: Buffer.from(module).toString("hex").padStart(64, "0"),
|
||||
formatter: (_str) => module
|
||||
})
|
||||
.uint8("type", {
|
||||
assert: 1,
|
||||
formatter: (_action) => "RegisterChain"
|
||||
})
|
||||
.uint16("chain")
|
||||
.uint16("emitterChain")
|
||||
.array("emitterAddress", {
|
||||
type: "uint8",
|
||||
lengthInBytes: 32,
|
||||
// formatter: (arr) => Buffer.from(arr).toString("hex")
|
||||
})
|
||||
.string("end", {
|
||||
greedy: true,
|
||||
assert: str => str === ""
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
function serialisePortalRegisterChain<Module extends "NFTBridge" | "TokenBridge">(payload: PortalRegisterChain<Module>): string {
|
||||
const body = [
|
||||
encode("bytes32", encodeString(payload.module)),
|
||||
encode("uint8", 1),
|
||||
encode("uint16", payload.chain),
|
||||
encode("uint16", payload.emitterChain),
|
||||
encode("bytes32", payload.emitterAddress)
|
||||
]
|
||||
return body.join("")
|
||||
}
|
||||
|
||||
// This function should be called after pattern matching on all possible options
|
||||
// of an enum (union) type, so that typescript can derive that no other options
|
||||
// are possible. If (from JavaScript land) an unsupported argument is passed
|
||||
// in, this function just throws. If the enum type is extended with new cases,
|
||||
// the call to this function will then fail to compile, drawing attention to an
|
||||
// unhandled case somewhere.
|
||||
export function impossible(a: never): any {
|
||||
throw new Error(`Impossible: ${a}`)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Encoder utils
|
||||
|
||||
type Encoding
|
||||
= "uint8"
|
||||
| "uint16"
|
||||
| "uint32"
|
||||
| "uint64"
|
||||
| "bytes32"
|
||||
|
||||
function typeWidth(type: Encoding): number {
|
||||
switch (type) {
|
||||
case "uint8": return 1
|
||||
case "uint16": return 2
|
||||
case "uint32": return 4
|
||||
case "uint64": return 8
|
||||
case "bytes32": return 32
|
||||
}
|
||||
}
|
||||
|
||||
// Couldn't find a satisfactory binary serialisation solution, so we just use
|
||||
// the ethers library's encoding logic
|
||||
function encode(type: Encoding, val: any): string {
|
||||
// ethers operates on hex strings (sigh) and left pads everything to 32
|
||||
// bytes (64 characters). We take last 2*n characters where n is the width
|
||||
// of the type being serialised in bytes (since a byte is represented as 2
|
||||
// digits in hex).
|
||||
return ethers.utils.defaultAbiCoder.encode([type], [val]).substr(-2 * typeWidth(type))
|
||||
}
|
||||
|
||||
// Encode a string as binary left-padded to 32 bytes, represented as a hex
|
||||
// string (64 chars long)
|
||||
function encodeString(str: string): Buffer {
|
||||
return Buffer.from(Buffer.from(str).toString("hex").padStart(64, "0"), "hex")
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
#!/bin/bash
|
||||
|
||||
usage="Usage:
|
||||
$(basename "$0") [sequence]
|
||||
|
||||
Fetch a governance VAA by sequence number, and print it as hex."
|
||||
|
||||
sequence=$1
|
||||
if [ -z "$sequence" ]; then
|
||||
echo "$usage"
|
||||
exit 1
|
||||
fi
|
||||
mkdir -p "$TMPDIR/vaa"
|
||||
cached="$TMPDIR/vaa/$sequence"
|
||||
|
||||
# We cache the result once it's ready, so we don't keep making requests if the
|
||||
# VAA has already been pulled
|
||||
if [ ! -f "$cached" ]; then
|
||||
result=$(curl -s "https://wormhole-v2-mainnet-api.certus.one/v1/signed_vaa/1/0000000000000000000000000000000000000000000000000000000000000004/$sequence" | jq '.vaaBytes' -r)
|
||||
# The 'vaaBytes' field is set once quorum has been reached. Otherwise, 'jq'
|
||||
# returns "null", in which case we just exit 1
|
||||
if [ "$result" == "null" ]; then
|
||||
exit 1
|
||||
fi
|
||||
# vaaBytes is base64, we convert it to hex and write it to cache
|
||||
echo "$result" | base64 -d | hexdump -v -e '/1 "%02x" ' > "$cached"
|
||||
fi
|
||||
|
||||
cat "$cached"
|
|
@ -1,29 +0,0 @@
|
|||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "main.ts generate-register-chain-vaa",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"args": [
|
||||
"${workspaceFolder}/main.ts",
|
||||
"generate_register_chain_vaa",
|
||||
"1",
|
||||
"0x00000000000000000000000026b4afb60d6c903165150c6f0aa14f8016be4aec",
|
||||
"--guardian_secret",
|
||||
"cfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0,c3b2e45c422a1602333a64078aeb42637370b0f48fe385f9cfa6ad54a8e0c47e,9f790d3f08bc4b5cd910d4278f3deb406e57bb5e924906ccd52052bb078ccd47,b20cc49d6f2c82a5e6519015fc18aa3e562867f85f872c58f1277cfbd2a0c8e4",
|
||||
],
|
||||
"runtimeArgs": [
|
||||
"--nolazy",
|
||||
"-r",
|
||||
"${workspaceRoot}/node_modules/ts-node/register"
|
||||
],
|
||||
"sourceMaps": true,
|
||||
"cwd": "${workspaceRoot}",
|
||||
"protocol": "inspector",
|
||||
},
|
||||
]
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
### usage
|
||||
|
||||
either build the typescript to javascript to run:
|
||||
|
||||
npm run build && node main.js solana execute_governance_vaa vaaHex...
|
||||
|
||||
or, run the typescript with ts-node:
|
||||
|
||||
npm run main -- solana execute_governance_vaa vaaHex...
|
|
@ -1,376 +0,0 @@
|
|||
import yargs from "yargs";
|
||||
|
||||
import { hideBin } from 'yargs/helpers'
|
||||
|
||||
import * as elliptic from "elliptic";
|
||||
import * as ethers from "ethers";
|
||||
import * as web3s from '@solana/web3.js';
|
||||
|
||||
import { PublicKey, TransactionInstruction, AccountMeta, Keypair, Connection } from "@solana/web3.js";
|
||||
import { base58, solidityKeccak256 } from "ethers/lib/utils";
|
||||
|
||||
import { setDefaultWasm, importCoreWasm, importNftWasm, ixFromRust, BridgeImplementation__factory } from '@certusone/wormhole-sdk'
|
||||
setDefaultWasm("node")
|
||||
|
||||
const signAndEncodeVM = function (
|
||||
timestamp,
|
||||
nonce,
|
||||
emitterChainId,
|
||||
emitterAddress,
|
||||
sequence,
|
||||
data,
|
||||
signers,
|
||||
guardianSetIndex,
|
||||
consistencyLevel
|
||||
) {
|
||||
const body = [
|
||||
ethers.utils.defaultAbiCoder.encode(["uint32"], [timestamp]).substring(2 + (64 - 8)),
|
||||
ethers.utils.defaultAbiCoder.encode(["uint32"], [nonce]).substring(2 + (64 - 8)),
|
||||
ethers.utils.defaultAbiCoder.encode(["uint16"], [emitterChainId]).substring(2 + (64 - 4)),
|
||||
ethers.utils.defaultAbiCoder.encode(["bytes32"], [emitterAddress]).substring(2),
|
||||
ethers.utils.defaultAbiCoder.encode(["uint64"], [sequence]).substring(2 + (64 - 16)),
|
||||
ethers.utils.defaultAbiCoder.encode(["uint8"], [consistencyLevel]).substring(2 + (64 - 2)),
|
||||
data.substr(2)
|
||||
]
|
||||
|
||||
const hash = solidityKeccak256(["bytes"], [solidityKeccak256(["bytes"], ["0x" + body.join("")])])
|
||||
|
||||
let signatures = "";
|
||||
|
||||
for (let i in signers) {
|
||||
const ec = new elliptic.ec("secp256k1");
|
||||
const key = ec.keyFromPrivate(signers[i]);
|
||||
const signature = key.sign(Buffer.from(hash.substr(2), "hex"), { canonical: true });
|
||||
|
||||
const packSig = [
|
||||
ethers.utils.defaultAbiCoder.encode(["uint8"], [i]).substring(2 + (64 - 2)),
|
||||
zeroPadBytes(signature.r.toString(16), 32),
|
||||
zeroPadBytes(signature.s.toString(16), 32),
|
||||
ethers.utils.defaultAbiCoder.encode(["uint8"], [signature.recoveryParam]).substr(2 + (64 - 2)),
|
||||
]
|
||||
|
||||
signatures += packSig.join("")
|
||||
}
|
||||
|
||||
const vm = [
|
||||
ethers.utils.defaultAbiCoder.encode(["uint8"], [1]).substring(2 + (64 - 2)),
|
||||
ethers.utils.defaultAbiCoder.encode(["uint32"], [guardianSetIndex]).substring(2 + (64 - 8)),
|
||||
ethers.utils.defaultAbiCoder.encode(["uint8"], [signers.length]).substring(2 + (64 - 2)),
|
||||
|
||||
signatures,
|
||||
body.join("")
|
||||
].join("");
|
||||
|
||||
return vm
|
||||
}
|
||||
|
||||
function zeroPadBytes(value, length) {
|
||||
while (value.length < 2 * length) {
|
||||
value = "0" + value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
yargs(hideBin(process.argv))
|
||||
.command('generate_register_chain_vaa [chain_id] [contract_address]', 'create a VAA to register a chain (debug-only)', (yargs) => {
|
||||
return yargs
|
||||
.positional('chain_id', {
|
||||
describe: 'chain id to register',
|
||||
type: "number",
|
||||
required: true
|
||||
})
|
||||
.positional('contract_address', {
|
||||
describe: 'contract to register',
|
||||
type: "string",
|
||||
required: true
|
||||
})
|
||||
.option('guardian_secret', {
|
||||
describe: 'Guardian\'s secret key, CSV allowed',
|
||||
type: "string",
|
||||
default: "cfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0"
|
||||
})
|
||||
}, async (argv) => {
|
||||
let data = [
|
||||
"0x",
|
||||
"00000000000000000000000000000000000000000000004e4654427269646765", // NFT Bridge header
|
||||
"01",
|
||||
"0000",
|
||||
ethers.utils.defaultAbiCoder.encode(["uint16"], [argv.chain_id]).substring(2 + (64 - 4)),
|
||||
ethers.utils.defaultAbiCoder.encode(["bytes32"], [fmtAddress(String(argv.contract_address))]).substring(2),
|
||||
].join('')
|
||||
|
||||
const vm = signAndEncodeVM(
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000004",
|
||||
Math.floor(Math.random() * 100000000),
|
||||
data,
|
||||
argv.guardian_secret.split(','),
|
||||
0,
|
||||
0
|
||||
);
|
||||
|
||||
console.log(vm)
|
||||
})
|
||||
.command('generate_upgrade_chain_vaa [chain_id] [contract_address]', 'create a VAA to upgrade a chain (debug-only)', (yargs) => {
|
||||
return yargs
|
||||
.positional('chain_id', {
|
||||
describe: 'chain id to upgrade',
|
||||
type: "number",
|
||||
required: true
|
||||
})
|
||||
.positional('contract_address', {
|
||||
describe: 'contract to upgrade to',
|
||||
type: "string",
|
||||
required: true
|
||||
})
|
||||
.option('guardian_secret', {
|
||||
describe: 'Guardian\'s secret key, CSV allowed',
|
||||
type: "string",
|
||||
default: "cfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0"
|
||||
})
|
||||
}, async (argv) => {
|
||||
let data = [
|
||||
"0x",
|
||||
"00000000000000000000000000000000000000000000004e4654427269646765", // NFT Bridge header
|
||||
"02",
|
||||
ethers.utils.defaultAbiCoder.encode(["uint16"], [argv.chain_id]).substring(2 + (64 - 4)),
|
||||
ethers.utils.defaultAbiCoder.encode(["bytes32"], [fmtAddress(String(argv.contract_address))]).substring(2),
|
||||
].join('')
|
||||
|
||||
const vm = signAndEncodeVM(
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000004",
|
||||
Math.floor(Math.random() * 100000000),
|
||||
data,
|
||||
argv.guardian_secret.split(','),
|
||||
0,
|
||||
0
|
||||
);
|
||||
|
||||
console.log(vm)
|
||||
})
|
||||
.command('solana execute_governance_vaa [vaa]', 'execute a governance VAA on Solana', (yargs) => {
|
||||
return yargs
|
||||
.positional('vaa', {
|
||||
describe: 'vaa to post',
|
||||
type: "string",
|
||||
required: true
|
||||
})
|
||||
.option('rpc', {
|
||||
alias: 'u',
|
||||
type: 'string',
|
||||
description: 'URL of the Solana RPC',
|
||||
default: "http://localhost:8899"
|
||||
})
|
||||
.option('bridge', {
|
||||
alias: 'b',
|
||||
type: 'string',
|
||||
description: 'Bridge address',
|
||||
default: "Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o"
|
||||
})
|
||||
.option('nft_bridge', {
|
||||
alias: 't',
|
||||
type: 'string',
|
||||
description: 'NFT Bridge address',
|
||||
default: "NFTWqJR8YnRVqPDvTJrYuLrQDitTG5AScqbeghi4zSA"
|
||||
})
|
||||
.option('key', {
|
||||
alias: 'k',
|
||||
type: 'string',
|
||||
description: 'Private key of the wallet',
|
||||
required: false
|
||||
})
|
||||
}, async (argv) => {
|
||||
const bridge = await importCoreWasm()
|
||||
const nft_bridge = await importNftWasm()
|
||||
|
||||
let connection = setupConnection(argv);
|
||||
let bridge_id = new PublicKey(argv.bridge);
|
||||
let nft_bridge_id = new PublicKey(argv.nft_bridge);
|
||||
|
||||
var from: web3s.Keypair;
|
||||
if (argv.key) {
|
||||
from = web3s.Keypair.fromSecretKey(base58.decode(argv.key));
|
||||
} else {
|
||||
from = web3s.Keypair.generate();
|
||||
let airdropSignature = await connection.requestAirdrop(
|
||||
from.publicKey,
|
||||
web3s.LAMPORTS_PER_SOL,
|
||||
);
|
||||
await connection.confirmTransaction(airdropSignature);
|
||||
}
|
||||
|
||||
let vaa = Buffer.from(String(argv.vaa), "hex");
|
||||
await post_vaa(connection, bridge_id, from, vaa);
|
||||
|
||||
let parsed_vaa = await bridge.parse_vaa(vaa);
|
||||
let ix: TransactionInstruction;
|
||||
switch (parsed_vaa.payload[32]) {
|
||||
case 1:
|
||||
console.log("Registering chain")
|
||||
ix = nft_bridge.register_chain_ix(nft_bridge_id.toString(), bridge_id.toString(), from.publicKey.toString(), vaa);
|
||||
break
|
||||
case 2:
|
||||
console.log("Upgrading contract")
|
||||
ix = nft_bridge.upgrade_contract_ix(nft_bridge_id.toString(), bridge_id.toString(), from.publicKey.toString(), from.publicKey.toString(), vaa);
|
||||
break
|
||||
default:
|
||||
throw new Error("unknown governance action")
|
||||
}
|
||||
let transaction = new web3s.Transaction().add(ixFromRust(ix));
|
||||
|
||||
// Sign transaction, broadcast, and confirm
|
||||
let signature = await web3s.sendAndConfirmTransaction(
|
||||
connection,
|
||||
transaction,
|
||||
[from],
|
||||
{
|
||||
skipPreflight: true
|
||||
}
|
||||
);
|
||||
console.log('SIGNATURE', signature);
|
||||
})
|
||||
.command('eth execute_governance_vaa [vaa]', 'execute a governance VAA on evm', (yargs) => {
|
||||
return yargs
|
||||
.positional('vaa', {
|
||||
describe: 'vaa to post',
|
||||
type: "string",
|
||||
required: true
|
||||
})
|
||||
.option('rpc', {
|
||||
alias: 'u',
|
||||
type: 'string',
|
||||
description: 'URL of the ETH RPC',
|
||||
default: "http://localhost:8545"
|
||||
})
|
||||
.option('nft_bridge', {
|
||||
alias: 't',
|
||||
type: 'string',
|
||||
description: 'NFT Bridge address',
|
||||
default: "0x26b4afb60d6c903165150c6f0aa14f8016be4aec"
|
||||
})
|
||||
.option('key', {
|
||||
alias: 'k',
|
||||
type: 'string',
|
||||
description: 'Private key of the wallet',
|
||||
default: "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d"
|
||||
})
|
||||
}, async (argv) => {
|
||||
const bridge = await importCoreWasm()
|
||||
|
||||
let provider = new ethers.providers.JsonRpcProvider(argv.rpc)
|
||||
let signer = new ethers.Wallet(argv.key, provider)
|
||||
let t = new BridgeImplementation__factory(signer);
|
||||
let tb = t.attach(argv.nft_bridge);
|
||||
|
||||
let vaa = Buffer.from(String(argv.vaa), "hex");
|
||||
let parsed_vaa = await bridge.parse_vaa(vaa);
|
||||
|
||||
switch (parsed_vaa.payload[32]) {
|
||||
case 1:
|
||||
console.log("Registering chain")
|
||||
console.log("Hash: " + (await tb.registerChain(vaa)).hash)
|
||||
break
|
||||
case 2:
|
||||
console.log("Upgrading contract")
|
||||
console.log("Hash: " + (await tb.upgrade(vaa)).hash)
|
||||
break
|
||||
default:
|
||||
throw new Error("unknown governance action")
|
||||
}
|
||||
})
|
||||
.argv;
|
||||
|
||||
async function post_vaa(connection: Connection, bridge_id: PublicKey, payer: Keypair, vaa: Buffer) {
|
||||
const bridge = await importCoreWasm()
|
||||
|
||||
let bridge_state = await get_bridge_state(connection, bridge_id);
|
||||
let guardian_addr = new PublicKey(bridge.guardian_set_address(bridge_id.toString(), bridge_state.guardian_set_index));
|
||||
let acc = await connection.getAccountInfo(guardian_addr);
|
||||
if (acc?.data === undefined) {
|
||||
return
|
||||
}
|
||||
let guardian_data = bridge.parse_guardian_set(new Uint8Array(acc?.data));
|
||||
|
||||
let signature_set = Keypair.generate();
|
||||
let txs = bridge.verify_signatures_ix(bridge_id.toString(), payer.publicKey.toString(), bridge_state.guardian_set_index, guardian_data, signature_set.publicKey.toString(), vaa)
|
||||
// Add transfer instruction to transaction
|
||||
for (let tx of txs) {
|
||||
let ixs: Array<TransactionInstruction> = tx.map((v: any) => {
|
||||
return ixFromRust(v)
|
||||
})
|
||||
let transaction = new web3s.Transaction().add(ixs[0], ixs[1]);
|
||||
|
||||
// Sign transaction, broadcast, and confirm
|
||||
await web3s.sendAndConfirmTransaction(
|
||||
connection,
|
||||
transaction,
|
||||
[payer, signature_set],
|
||||
{
|
||||
skipPreflight: true
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
let ix = ixFromRust(bridge.post_vaa_ix(bridge_id.toString(), payer.publicKey.toString(), signature_set.publicKey.toString(), vaa));
|
||||
let transaction = new web3s.Transaction().add(ix);
|
||||
|
||||
// Sign transaction, broadcast, and confirm
|
||||
let signature = await web3s.sendAndConfirmTransaction(
|
||||
connection,
|
||||
transaction,
|
||||
[payer],
|
||||
{
|
||||
skipPreflight: true
|
||||
}
|
||||
);
|
||||
console.log('SIGNATURE', signature);
|
||||
}
|
||||
|
||||
async function get_bridge_state(connection: Connection, bridge_id: PublicKey): Promise<BridgeState> {
|
||||
const bridge = await importCoreWasm()
|
||||
|
||||
let bridge_state = new PublicKey(bridge.state_address(bridge_id.toString()));
|
||||
let acc = await connection.getAccountInfo(bridge_state);
|
||||
if (acc?.data === undefined) {
|
||||
throw new Error("bridge state not found")
|
||||
}
|
||||
return bridge.parse_state(new Uint8Array(acc?.data));
|
||||
}
|
||||
|
||||
function setupConnection(argv: yargs.Arguments): web3s.Connection {
|
||||
return new web3s.Connection(
|
||||
argv.rpc as string,
|
||||
'confirmed',
|
||||
);
|
||||
}
|
||||
|
||||
function fmtAddress(addr: string): string {
|
||||
let address = (addr.search("0x") == 0) ? addr.substring(2) : addr;
|
||||
return "0x" + zeroPadBytes(address, 32);
|
||||
}
|
||||
|
||||
interface BridgeState {
|
||||
// The current guardian set index, used to decide which signature sets to accept.
|
||||
guardian_set_index: number,
|
||||
|
||||
// Lamports in the collection account
|
||||
last_lamports: number,
|
||||
|
||||
// Bridge configuration, which is set once upon initialization.
|
||||
config: BridgeConfig,
|
||||
}
|
||||
|
||||
interface BridgeConfig {
|
||||
// Period for how long a guardian set is valid after it has been replaced by a new one. This
|
||||
// guarantees that VAAs issued by that set can still be submitted for a certain period. In
|
||||
// this period we still trust the old guardian set.
|
||||
guardian_set_expiration_time: number,
|
||||
|
||||
// Amount of lamports that needs to be paid to the protocol to post a message
|
||||
fee: number,
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,31 +0,0 @@
|
|||
{
|
||||
"name": "wormhole-client-solana",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@certusone/wormhole-sdk": "^0.2.0",
|
||||
"@solana/web3.js": "^1.22.0",
|
||||
"bn.js": "^5.2.0",
|
||||
"bs58": "^4.0.1",
|
||||
"buffer-layout": "^1.2.2",
|
||||
"ethers": "^5.4.1",
|
||||
"js-base64": "^3.6.1",
|
||||
"npm": "^7.20.0",
|
||||
"web3": "^1.5.0",
|
||||
"yargs": "^17.0.1"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "tsc && node main.js",
|
||||
"build": "tsc",
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"main": "ts-node main.ts"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@truffle/hdwallet-provider": "^1.4.1",
|
||||
"@types/bn.js": "^5.1.0",
|
||||
"@types/bs58": "^4.0.1",
|
||||
"@types/yargs": "^17.0.2",
|
||||
"copy-dir": "^1.3.0",
|
||||
"ts-node": "^10.7.0",
|
||||
"typescript": "^4.3.5"
|
||||
}
|
||||
}
|
|
@ -1,72 +0,0 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
/* Visit https://aka.ms/tsconfig.json to read more about this file */
|
||||
|
||||
/* Basic Options */
|
||||
// "incremental": true, /* Enable incremental compilation */
|
||||
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */
|
||||
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
|
||||
// "lib": [], /* Specify library files to be included in the compilation. */
|
||||
// "allowJs": true, /* Allow javascript files to be compiled. */
|
||||
// "checkJs": true, /* Report errors in .js files. */
|
||||
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */
|
||||
// "declaration": true, /* Generates corresponding '.d.ts' file. */
|
||||
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
||||
// "sourceMap": true, /* Generates corresponding '.map' file. */
|
||||
// "outFile": "./", /* Concatenate and emit output to single file. */
|
||||
// "outDir": "./", /* Redirect output structure to the directory. */
|
||||
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
||||
// "composite": true, /* Enable project compilation */
|
||||
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
|
||||
// "removeComments": true, /* Do not emit comments to output. */
|
||||
// "noEmit": true, /* Do not emit outputs. */
|
||||
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
|
||||
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
|
||||
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
|
||||
|
||||
/* Strict Type-Checking Options */
|
||||
"strict": true, /* Enable all strict type-checking options. */
|
||||
"noImplicitAny": false, /* Raise error on expressions and declarations with an implied 'any' type. */
|
||||
// "strictNullChecks": true, /* Enable strict null checks. */
|
||||
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
|
||||
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
|
||||
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
|
||||
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
|
||||
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
|
||||
|
||||
/* Additional Checks */
|
||||
// "noUnusedLocals": true, /* Report errors on unused locals. */
|
||||
// "noUnusedParameters": true, /* Report errors on unused parameters. */
|
||||
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
|
||||
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
||||
// "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
|
||||
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an 'override' modifier. */
|
||||
// "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */
|
||||
|
||||
/* Module Resolution Options */
|
||||
"moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
|
||||
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
|
||||
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
||||
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
||||
// "typeRoots": [], /* List of folders to include type definitions from. */
|
||||
// "types": [], /* Type declaration files to be included in compilation. */
|
||||
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
|
||||
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
||||
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
|
||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||
|
||||
/* Source Map Options */
|
||||
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
|
||||
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
|
||||
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
|
||||
|
||||
/* Experimental Options */
|
||||
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
|
||||
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
|
||||
|
||||
/* Advanced Options */
|
||||
"skipLibCheck": true, /* Skip type checking of declaration files. */
|
||||
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
|
||||
}
|
||||
}
|
|
@ -1,260 +0,0 @@
|
|||
import yargs from "yargs";
|
||||
|
||||
import { hideBin } from 'yargs/helpers';
|
||||
import * as web3 from '@solana/web3.js';
|
||||
import { PublicKey, TransactionInstruction, Keypair, Connection } from "@solana/web3.js";
|
||||
import { base58 } from "ethers/lib/utils";
|
||||
|
||||
import { setDefaultWasm, importCoreWasm, ixFromRust } from '@certusone/wormhole-sdk'
|
||||
setDefaultWasm("node")
|
||||
|
||||
yargs(hideBin(process.argv))
|
||||
.command('post_message [nonce] [message] [consistency]', 'post a message', (yargs) => {
|
||||
return yargs
|
||||
.positional('nonce', {
|
||||
describe: 'nonce of the message',
|
||||
type: "number",
|
||||
required: true
|
||||
})
|
||||
.positional('message', {
|
||||
describe: 'message to post',
|
||||
type: "string",
|
||||
required: true
|
||||
})
|
||||
.positional('consistency', {
|
||||
describe: 'confirmation level that this message requires <CONFIRMED|FINALIZED>',
|
||||
type: "string",
|
||||
required: true
|
||||
})
|
||||
}, async (argv: any) => {
|
||||
const bridge = await importCoreWasm()
|
||||
|
||||
let connection = setupConnection(argv);
|
||||
let bridge_id = new PublicKey(argv.bridge);
|
||||
|
||||
// Generate a new random public key
|
||||
let from = web3.Keypair.generate();
|
||||
let emitter = web3.Keypair.generate();
|
||||
let message = web3.Keypair.generate();
|
||||
let airdropSignature = await connection.requestAirdrop(
|
||||
from.publicKey,
|
||||
web3.LAMPORTS_PER_SOL,
|
||||
);
|
||||
await connection.confirmTransaction(airdropSignature);
|
||||
|
||||
let fee_acc = bridge.fee_collector_address(bridge_id.toString());
|
||||
let bridge_state = await get_bridge_state(connection, bridge_id);
|
||||
let transferIx = web3.SystemProgram.transfer({
|
||||
fromPubkey: from.publicKey,
|
||||
toPubkey: new PublicKey(fee_acc),
|
||||
lamports: bridge_state.config.fee,
|
||||
});
|
||||
|
||||
if (argv.consistency !== "CONFIRMED" && argv.consistency !== "FINALIZED") {
|
||||
throw new Error("invalid consistency level")
|
||||
}
|
||||
|
||||
let ix = ixFromRust(bridge.post_message_ix(bridge_id.toString(), from.publicKey.toString(), emitter.publicKey.toString(), message.publicKey.toString(), argv.nonce, Buffer.from(argv.message, "hex"), argv.consistency));
|
||||
// Add transfer instruction to transaction
|
||||
let transaction = new web3.Transaction().add(transferIx, ix);
|
||||
|
||||
// Sign transaction, broadcast, and confirm
|
||||
let signature = await web3.sendAndConfirmTransaction(
|
||||
connection,
|
||||
transaction,
|
||||
[from, emitter, message],
|
||||
{
|
||||
skipPreflight: true
|
||||
}
|
||||
);
|
||||
console.log('SIGNATURE', signature);
|
||||
})
|
||||
.command('post_vaa [vaa]', 'post a VAA on Solana', (yargs) => {
|
||||
return yargs
|
||||
.positional('vaa', {
|
||||
describe: 'vaa to post',
|
||||
type: "string",
|
||||
required: true
|
||||
})
|
||||
}, async (argv: any) => {
|
||||
let connection = setupConnection(argv);
|
||||
let bridge_id = new PublicKey(argv.bridge);
|
||||
|
||||
// Generate a new random public key
|
||||
let from = web3.Keypair.generate();
|
||||
let airdropSignature = await connection.requestAirdrop(
|
||||
from.publicKey,
|
||||
web3.LAMPORTS_PER_SOL,
|
||||
);
|
||||
await connection.confirmTransaction(airdropSignature);
|
||||
|
||||
let vaa = Buffer.from(argv.vaa, "hex");
|
||||
await post_vaa(connection, bridge_id, from, vaa);
|
||||
})
|
||||
.command('execute_governance_vaa [vaa]', 'execute a governance VAA on Solana', (yargs) => {
|
||||
return yargs
|
||||
.positional('vaa', {
|
||||
describe: 'vaa to post',
|
||||
type: "string",
|
||||
required: true
|
||||
})
|
||||
}, async (argv: any) => {
|
||||
const bridge = await importCoreWasm()
|
||||
|
||||
let connection = setupConnection(argv);
|
||||
let bridge_id = new PublicKey(argv.bridge);
|
||||
|
||||
var from: web3.Keypair;
|
||||
if (argv.key) {
|
||||
from = web3.Keypair.fromSecretKey(base58.decode(argv.key));
|
||||
} else {
|
||||
from = web3.Keypair.generate();
|
||||
let airdropSignature = await connection.requestAirdrop(
|
||||
from.publicKey,
|
||||
web3.LAMPORTS_PER_SOL,
|
||||
);
|
||||
await connection.confirmTransaction(airdropSignature);
|
||||
}
|
||||
|
||||
let vaa = Buffer.from(argv.vaa, "hex");
|
||||
await post_vaa(connection, bridge_id, from, vaa);
|
||||
|
||||
let parsed_vaa = await bridge.parse_vaa(vaa);
|
||||
let ix: TransactionInstruction;
|
||||
switch (parsed_vaa.payload[32]) {
|
||||
case 1:
|
||||
console.log("Upgrading contract")
|
||||
ix = bridge.upgrade_contract_ix(bridge_id.toString(), from.publicKey.toString(), from.publicKey.toString(), vaa);
|
||||
break
|
||||
case 2:
|
||||
console.log("Updating guardian set")
|
||||
ix = bridge.update_guardian_set_ix(bridge_id.toString(), from.publicKey.toString(), vaa);
|
||||
break
|
||||
case 3:
|
||||
console.log("Setting fees")
|
||||
ix = bridge.set_fees_ix(bridge_id.toString(), from.publicKey.toString(), vaa);
|
||||
break
|
||||
case 4:
|
||||
console.log("Transferring fees")
|
||||
ix = bridge.transfer_fees_ix(bridge_id.toString(), from.publicKey.toString(), vaa);
|
||||
break
|
||||
default:
|
||||
throw new Error("unknown governance action")
|
||||
}
|
||||
let transaction = new web3.Transaction().add(ixFromRust(ix));
|
||||
|
||||
// Sign transaction, broadcast, and confirm
|
||||
let signature = await web3.sendAndConfirmTransaction(
|
||||
connection,
|
||||
transaction,
|
||||
[from],
|
||||
{
|
||||
skipPreflight: true
|
||||
}
|
||||
);
|
||||
console.log('SIGNATURE', signature);
|
||||
})
|
||||
.option('rpc', {
|
||||
alias: 'u',
|
||||
type: 'string',
|
||||
description: 'URL of the Solana RPC',
|
||||
default: "http://localhost:8899"
|
||||
})
|
||||
.option('bridge', {
|
||||
alias: 'b',
|
||||
type: 'string',
|
||||
description: 'Bridge address',
|
||||
default: "Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o"
|
||||
})
|
||||
.option('key', {
|
||||
alias: 'k',
|
||||
type: 'string',
|
||||
description: 'Private key of the wallet',
|
||||
required: false
|
||||
})
|
||||
.argv;
|
||||
|
||||
async function post_vaa(connection: Connection, bridge_id: PublicKey, payer: Keypair, vaa: Buffer) {
|
||||
const bridge = await importCoreWasm()
|
||||
|
||||
let bridge_state = await get_bridge_state(connection, bridge_id);
|
||||
let guardian_addr = new PublicKey(bridge.guardian_set_address(bridge_id.toString(), bridge_state.guardian_set_index));
|
||||
let acc = await connection.getAccountInfo(guardian_addr);
|
||||
if (acc?.data === undefined) {
|
||||
return
|
||||
}
|
||||
let guardian_data = bridge.parse_guardian_set(new Uint8Array(acc?.data));
|
||||
|
||||
let signature_set = Keypair.generate();
|
||||
let txs = bridge.verify_signatures_ix(bridge_id.toString(), payer.publicKey.toString(), bridge_state.guardian_set_index, guardian_data, signature_set.publicKey.toString(), vaa)
|
||||
// Add transfer instruction to transaction
|
||||
for (let tx of txs) {
|
||||
let ixs: Array<TransactionInstruction> = tx.map((v: any) => {
|
||||
return ixFromRust(v)
|
||||
})
|
||||
let transaction = new web3.Transaction().add(ixs[0], ixs[1]);
|
||||
|
||||
// Sign transaction, broadcast, and confirm
|
||||
await web3.sendAndConfirmTransaction(
|
||||
connection,
|
||||
transaction,
|
||||
[payer, signature_set],
|
||||
{
|
||||
skipPreflight: true
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
let ix = ixFromRust(bridge.post_vaa_ix(bridge_id.toString(), payer.publicKey.toString(), signature_set.publicKey.toString(), vaa));
|
||||
let transaction = new web3.Transaction().add(ix);
|
||||
|
||||
// Sign transaction, broadcast, and confirm
|
||||
let signature = await web3.sendAndConfirmTransaction(
|
||||
connection,
|
||||
transaction,
|
||||
[payer],
|
||||
{
|
||||
skipPreflight: true
|
||||
}
|
||||
);
|
||||
console.log('SIGNATURE', signature);
|
||||
}
|
||||
|
||||
async function get_bridge_state(connection: Connection, bridge_id: PublicKey): Promise<BridgeState> {
|
||||
const bridge = await importCoreWasm()
|
||||
|
||||
let bridge_state = new PublicKey(bridge.state_address(bridge_id.toString()));
|
||||
let acc = await connection.getAccountInfo(bridge_state);
|
||||
if (acc?.data === undefined) {
|
||||
throw new Error("bridge state not found")
|
||||
}
|
||||
return bridge.parse_state(new Uint8Array(acc?.data));
|
||||
}
|
||||
|
||||
function setupConnection(argv: yargs.Arguments): web3.Connection {
|
||||
return new web3.Connection(
|
||||
argv.rpc as string,
|
||||
'confirmed',
|
||||
);
|
||||
}
|
||||
|
||||
interface BridgeState {
|
||||
// The current guardian set index, used to decide which signature sets to accept.
|
||||
guardian_set_index: number,
|
||||
|
||||
// Lamports in the collection account
|
||||
last_lamports: number,
|
||||
|
||||
// Bridge configuration, which is set once upon initialization.
|
||||
config: BridgeConfig,
|
||||
}
|
||||
|
||||
interface BridgeConfig {
|
||||
// Period for how long a guardian set is valid after it has been replaced by a new one. This
|
||||
// guarantees that VAAs issued by that set can still be submitted for a certain period. In
|
||||
// this period we still trust the old guardian set.
|
||||
guardian_set_expiration_time: number,
|
||||
|
||||
// Amount of lamports that needs to be paid to the protocol to post a message
|
||||
fee: number,
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,25 +0,0 @@
|
|||
{
|
||||
"name": "wormhole-client-solana",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@certusone/wormhole-sdk": "^0.2.0",
|
||||
"@solana/web3.js": "^1.22.0",
|
||||
"bn.js": "^5.2.0",
|
||||
"bs58": "^4.0.1",
|
||||
"buffer-layout": "^1.2.2",
|
||||
"ethers": "^5.4.1",
|
||||
"npm": "^7.20.0",
|
||||
"yargs": "^17.0.1"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "tsc && node main.js",
|
||||
"build": "tsc",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bn.js": "^5.1.0",
|
||||
"@types/bs58": "^4.0.1",
|
||||
"@types/yargs": "^17.0.2",
|
||||
"typescript": "^4.3.5"
|
||||
}
|
||||
}
|
|
@ -1,115 +0,0 @@
|
|||
import argparse
|
||||
from terra_sdk.client.lcd import AsyncLCDClient
|
||||
import asyncio
|
||||
from terra_sdk.core.wasm import (
|
||||
MsgExecuteContract,
|
||||
)
|
||||
from terra_sdk.key.mnemonic import MnemonicKey
|
||||
import base64
|
||||
|
||||
|
||||
def add_default_args(parser):
|
||||
parser.add_argument('--rpc', required=True, help='Terra lcd address')
|
||||
parser.add_argument('--chain-id', dest="chain_id", required=True, help='Chain ID')
|
||||
parser.add_argument('--mnemonic', dest="mnemonic", required=True, help='Mnemonic of the wallet to be used')
|
||||
parser.add_argument('--contract', dest="contract", required=True, help='Address of the Wormhole contract')
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser(prog='terra_cli')
|
||||
|
||||
subparsers = parser.add_subparsers(help='sub-command help', dest="command")
|
||||
gov_parser = subparsers.add_parser('execute_governance', help='Execute a governance VAA')
|
||||
add_default_args(gov_parser)
|
||||
gov_parser.add_argument('vaa', help='Hex encoded VAA')
|
||||
post_parser = subparsers.add_parser('post_message', help='Publish a message over the wormhole')
|
||||
add_default_args(post_parser)
|
||||
post_parser.add_argument('nonce', help='Nonce of the message', type=int)
|
||||
post_parser.add_argument('message', help='Hex-encoded message')
|
||||
|
||||
gas_prices = {
|
||||
"uluna": "0.15",
|
||||
"usdr": "0.1018",
|
||||
"uusd": "0.15",
|
||||
"ukrw": "178.05",
|
||||
"umnt": "431.6259",
|
||||
"ueur": "0.125",
|
||||
"ucny": "0.97",
|
||||
"ujpy": "16",
|
||||
"ugbp": "0.11",
|
||||
"uinr": "11",
|
||||
"ucad": "0.19",
|
||||
"uchf": "0.13",
|
||||
"uaud": "0.19",
|
||||
"usgd": "0.2",
|
||||
}
|
||||
|
||||
|
||||
async def sign_and_broadcast(sequence, deployer, terra, *msgs):
|
||||
tx = await deployer.create_and_sign_tx(
|
||||
msgs=msgs, fee_denoms=["ukrw", "uusd", "uluna"], sequence=sequence, gas_adjustment=1.4,
|
||||
)
|
||||
result = await terra.tx.broadcast(tx)
|
||||
sequence += 1
|
||||
if result.is_tx_error():
|
||||
raise RuntimeError(result.raw_log)
|
||||
return result
|
||||
|
||||
|
||||
class ContractQuerier:
|
||||
def __init__(self, address, terra):
|
||||
self.address = address
|
||||
self.terra = terra
|
||||
|
||||
def __getattr__(self, item):
|
||||
async def result_fxn(**kwargs):
|
||||
return await self.terra.wasm.contract_query(self.address, {item: kwargs})
|
||||
|
||||
return result_fxn
|
||||
|
||||
|
||||
class Contract:
|
||||
def __init__(self, address, deployer, terra, sequence):
|
||||
self.address = address
|
||||
self.deployer = deployer
|
||||
self.terra = terra
|
||||
self.sequence = sequence
|
||||
|
||||
def __getattr__(self, item):
|
||||
async def result_fxn(coins=None, **kwargs):
|
||||
execute = MsgExecuteContract(
|
||||
self.deployer.key.acc_address, self.address, {item: kwargs}, coins=coins
|
||||
)
|
||||
return await sign_and_broadcast(self.sequence, self.deployer, self.terra, execute)
|
||||
|
||||
return result_fxn
|
||||
|
||||
@property
|
||||
def query(self):
|
||||
return ContractQuerier(self.address, self.terra)
|
||||
|
||||
|
||||
async def main():
|
||||
args = parser.parse_args()
|
||||
async with AsyncLCDClient(
|
||||
args.rpc, args.chain_id, gas_prices=gas_prices, loop=asyncio.get_event_loop()
|
||||
) as terra:
|
||||
deployer = terra.wallet(MnemonicKey(
|
||||
mnemonic=args.mnemonic))
|
||||
sequence = await deployer.sequence()
|
||||
|
||||
wormhole = Contract(args.contract, deployer, terra, sequence)
|
||||
|
||||
res = dict()
|
||||
if args.command == "execute_governance":
|
||||
res = await wormhole.submit_v_a_a(vaa=base64.b64encode(bytes.fromhex(args.vaa)).decode("utf-8"))
|
||||
elif args.command == "post_message":
|
||||
state = await wormhole.query.get_state()
|
||||
fee = state["fee"]
|
||||
res = await wormhole.post_message(nonce=args.nonce,
|
||||
message=base64.b64encode(bytes.fromhex(args.message)).decode("utf-8"),
|
||||
coins={fee["denom"]: fee["amount"]})
|
||||
print(res.logs[0].events_by_type["from_contract"])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.get_event_loop().run_until_complete(main())
|
|
@ -1 +0,0 @@
|
|||
terra_sdk==0.14.0
|
|
@ -1,9 +0,0 @@
|
|||
### usage
|
||||
|
||||
either build the typescript to javascript to run:
|
||||
|
||||
npm run build && node main.js solana execute_governance_vaa vaaHex...
|
||||
|
||||
or, run the typescript with ts-node:
|
||||
|
||||
npm run main -- solana execute_governance_vaa vaaHex...
|
|
@ -1,450 +0,0 @@
|
|||
import yargs from "yargs";
|
||||
|
||||
import { hideBin } from 'yargs/helpers';
|
||||
|
||||
import * as elliptic from "elliptic";
|
||||
import * as ethers from "ethers";
|
||||
import * as web3s from '@solana/web3.js';
|
||||
|
||||
import { fromUint8Array } from "js-base64";
|
||||
import { LCDClient, MnemonicKey } from '@terra-money/terra.js';
|
||||
import { MsgExecuteContract } from "@terra-money/terra.js";
|
||||
import { PublicKey, TransactionInstruction, Keypair, Connection } from "@solana/web3.js";
|
||||
import { base58, solidityKeccak256 } from "ethers/lib/utils";
|
||||
|
||||
import { setDefaultWasm, importCoreWasm, importTokenWasm, ixFromRust, BridgeImplementation__factory } from '@certusone/wormhole-sdk'
|
||||
setDefaultWasm("node")
|
||||
|
||||
const signAndEncodeVM = function (
|
||||
timestamp,
|
||||
nonce,
|
||||
emitterChainId,
|
||||
emitterAddress,
|
||||
sequence,
|
||||
data,
|
||||
signers,
|
||||
guardianSetIndex,
|
||||
consistencyLevel
|
||||
) {
|
||||
const body = [
|
||||
ethers.utils.defaultAbiCoder.encode(["uint32"], [timestamp]).substring(2 + (64 - 8)),
|
||||
ethers.utils.defaultAbiCoder.encode(["uint32"], [nonce]).substring(2 + (64 - 8)),
|
||||
ethers.utils.defaultAbiCoder.encode(["uint16"], [emitterChainId]).substring(2 + (64 - 4)),
|
||||
ethers.utils.defaultAbiCoder.encode(["bytes32"], [emitterAddress]).substring(2),
|
||||
ethers.utils.defaultAbiCoder.encode(["uint64"], [sequence]).substring(2 + (64 - 16)),
|
||||
ethers.utils.defaultAbiCoder.encode(["uint8"], [consistencyLevel]).substring(2 + (64 - 2)),
|
||||
data.substr(2)
|
||||
]
|
||||
|
||||
const hash = solidityKeccak256(["bytes"], [solidityKeccak256(["bytes"], ["0x" + body.join("")])])
|
||||
|
||||
let signatures = "";
|
||||
|
||||
for (let i in signers) {
|
||||
const ec = new elliptic.ec("secp256k1");
|
||||
const key = ec.keyFromPrivate(signers[i]);
|
||||
const signature = key.sign(Buffer.from(hash.substr(2), "hex"), { canonical: true });
|
||||
|
||||
const packSig = [
|
||||
ethers.utils.defaultAbiCoder.encode(["uint8"], [i]).substring(2 + (64 - 2)),
|
||||
zeroPadBytes(signature.r.toString(16), 32),
|
||||
zeroPadBytes(signature.s.toString(16), 32),
|
||||
ethers.utils.defaultAbiCoder.encode(["uint8"], [signature.recoveryParam]).substr(2 + (64 - 2)),
|
||||
]
|
||||
|
||||
signatures += packSig.join("")
|
||||
}
|
||||
|
||||
const vm = [
|
||||
ethers.utils.defaultAbiCoder.encode(["uint8"], [1]).substring(2 + (64 - 2)),
|
||||
ethers.utils.defaultAbiCoder.encode(["uint32"], [guardianSetIndex]).substring(2 + (64 - 8)),
|
||||
ethers.utils.defaultAbiCoder.encode(["uint8"], [signers.length]).substring(2 + (64 - 2)),
|
||||
|
||||
signatures,
|
||||
body.join("")
|
||||
].join("");
|
||||
|
||||
return vm
|
||||
}
|
||||
|
||||
function zeroPadBytes(value, length) {
|
||||
while (value.length < 2 * length) {
|
||||
value = "0" + value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
yargs(hideBin(process.argv))
|
||||
.command('generate_register_chain_vaa [chain_id] [contract_address]', 'create a VAA to register a chain (debug-only)', (yargs) => {
|
||||
return yargs
|
||||
.positional('chain_id', {
|
||||
describe: 'chain id to register',
|
||||
type: "number",
|
||||
required: true
|
||||
})
|
||||
.positional('contract_address', {
|
||||
describe: 'contract to register',
|
||||
type: "string",
|
||||
required: true
|
||||
})
|
||||
.option('guardian_secret', {
|
||||
describe: 'Guardian\'s secret key, CSV allowed',
|
||||
type: "string",
|
||||
default: "cfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0"
|
||||
})
|
||||
}, async (argv) => {
|
||||
let data = [
|
||||
"0x",
|
||||
"000000000000000000000000000000000000000000546f6b656e427269646765", // Token Bridge header
|
||||
"01",
|
||||
"0000",
|
||||
ethers.utils.defaultAbiCoder.encode(["uint16"], [argv.chain_id]).substring(2 + (64 - 4)),
|
||||
ethers.utils.defaultAbiCoder.encode(["bytes32"], [fmtAddress(String(argv.contract_address))]).substring(2),
|
||||
].join('')
|
||||
|
||||
const vm = signAndEncodeVM(
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000004",
|
||||
Math.floor(Math.random() * 100000000),
|
||||
data,
|
||||
argv.guardian_secret.split(','),
|
||||
0,
|
||||
0
|
||||
);
|
||||
|
||||
console.log(vm)
|
||||
})
|
||||
.command('generate_upgrade_chain_vaa [chain_id] [contract_address]', 'create a VAA to upgrade a chain (debug-only)', (yargs) => {
|
||||
return yargs
|
||||
.positional('chain_id', {
|
||||
describe: 'chain id to upgrade',
|
||||
type: "number",
|
||||
required: true
|
||||
})
|
||||
.positional('contract_address', {
|
||||
describe: 'contract to upgrade to',
|
||||
type: "string",
|
||||
required: true
|
||||
})
|
||||
.option('guardian_secret', {
|
||||
describe: 'Guardian\'s secret key, CSV allowed',
|
||||
type: "string",
|
||||
default: "cfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0"
|
||||
})
|
||||
}, async (argv) => {
|
||||
let data = [
|
||||
"0x",
|
||||
"000000000000000000000000000000000000000000546f6b656e427269646765", // Token Bridge header
|
||||
"02",
|
||||
ethers.utils.defaultAbiCoder.encode(["uint16"], [argv.chain_id]).substring(2 + (64 - 4)),
|
||||
ethers.utils.defaultAbiCoder.encode(["bytes32"], [fmtAddress(String(argv.contract_address))]).substring(2),
|
||||
].join('')
|
||||
|
||||
const vm = signAndEncodeVM(
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000004",
|
||||
Math.floor(Math.random() * 100000000),
|
||||
data,
|
||||
argv.guardian_secret.split(','),
|
||||
0,
|
||||
0
|
||||
);
|
||||
|
||||
console.log(vm)
|
||||
})
|
||||
.command('terra execute_governance_vaa [vaa]', 'execute a governance VAA on Terra', (yargs) => {
|
||||
return yargs
|
||||
.positional('vaa', {
|
||||
describe: 'vaa to post',
|
||||
type: "string",
|
||||
required: true
|
||||
})
|
||||
.option('rpc', {
|
||||
alias: 'u',
|
||||
type: 'string',
|
||||
description: 'URL of the Terra RPC',
|
||||
default: "http://localhost:1317"
|
||||
})
|
||||
.option('token_bridge', {
|
||||
alias: 't',
|
||||
type: 'string',
|
||||
description: 'Token Bridge address',
|
||||
default: "terra10pyejy66429refv3g35g2t7am0was7ya7kz2a4"
|
||||
})
|
||||
.option('chain_id', {
|
||||
alias: 'c',
|
||||
type: 'string',
|
||||
description: 'Chain ID',
|
||||
// Should be localterra in theory, however Terra Station will
|
||||
// assume columbus-4 when localterra is set, while our current
|
||||
// dev environment is based on columbus-4. Should change when
|
||||
// change ID within terra/devnet/config/genesis.json is also
|
||||
// changed.
|
||||
default: 'columbus-4'
|
||||
})
|
||||
.option('mnemonic', {
|
||||
alias: 'm',
|
||||
type: 'string',
|
||||
description: 'Wallet Mnemonic',
|
||||
default: 'notice oak worry limit wrap speak medal online prefer cluster roof addict wrist behave treat actual wasp year salad speed social layer crew genius',
|
||||
})
|
||||
}, async (argv) => {
|
||||
const terra = new LCDClient({
|
||||
URL: argv.rpc,
|
||||
chainID: argv.chain_id,
|
||||
});
|
||||
|
||||
const wallet = terra.wallet(new MnemonicKey({
|
||||
mnemonic: argv.mnemonic
|
||||
}));
|
||||
|
||||
// create a simple message that moves coin balances
|
||||
const vaa = Buffer.from(String(argv.vaa), "hex");
|
||||
const transaction = new MsgExecuteContract(
|
||||
wallet.key.accAddress,
|
||||
argv.token_bridge,
|
||||
{
|
||||
submit_vaa: {
|
||||
data: fromUint8Array(vaa)
|
||||
},
|
||||
},
|
||||
{ uluna: 1000 }
|
||||
);
|
||||
|
||||
wallet
|
||||
.createAndSignTx({
|
||||
msgs: [transaction],
|
||||
memo: '',
|
||||
})
|
||||
.then(tx => terra.tx.broadcast(tx))
|
||||
.then(result => {
|
||||
console.log(result);
|
||||
console.log(`TX hash: ${result.txhash}`);
|
||||
});
|
||||
})
|
||||
.command('solana execute_governance_vaa [vaa]', 'execute a governance VAA on Solana', (yargs) => {
|
||||
return yargs
|
||||
.positional('vaa', {
|
||||
describe: 'vaa to post',
|
||||
type: "string",
|
||||
required: true
|
||||
})
|
||||
.option('rpc', {
|
||||
alias: 'u',
|
||||
type: 'string',
|
||||
description: 'URL of the Solana RPC',
|
||||
default: "http://localhost:8899"
|
||||
})
|
||||
.option('bridge', {
|
||||
alias: 'b',
|
||||
type: 'string',
|
||||
description: 'Bridge address',
|
||||
default: "Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o"
|
||||
})
|
||||
.option('token_bridge', {
|
||||
alias: 't',
|
||||
type: 'string',
|
||||
description: 'Token Bridge address',
|
||||
default: "B6RHG3mfcckmrYN1UhmJzyS1XX3fZKbkeUcpJe9Sy3FE"
|
||||
})
|
||||
.option('key', {
|
||||
alias: 'k',
|
||||
type: 'string',
|
||||
description: 'Private key of the wallet',
|
||||
required: false
|
||||
})
|
||||
}, async (argv) => {
|
||||
const bridge = await importCoreWasm()
|
||||
const token_bridge = await importTokenWasm()
|
||||
|
||||
let connection = setupConnection(argv);
|
||||
let bridge_id = new PublicKey(argv.bridge);
|
||||
let token_bridge_id = new PublicKey(argv.token_bridge);
|
||||
|
||||
var from: web3s.Keypair;
|
||||
if (argv.key) {
|
||||
from = web3s.Keypair.fromSecretKey(base58.decode(argv.key));
|
||||
} else {
|
||||
from = web3s.Keypair.generate();
|
||||
let airdropSignature = await connection.requestAirdrop(
|
||||
from.publicKey,
|
||||
web3s.LAMPORTS_PER_SOL,
|
||||
);
|
||||
await connection.confirmTransaction(airdropSignature);
|
||||
}
|
||||
|
||||
let vaa = Buffer.from(String(argv.vaa), "hex");
|
||||
await post_vaa(connection, bridge_id, from, vaa);
|
||||
|
||||
let parsed_vaa = await bridge.parse_vaa(vaa);
|
||||
let ix: TransactionInstruction;
|
||||
switch (parsed_vaa.payload[32]) {
|
||||
case 1:
|
||||
console.log("Registering chain")
|
||||
ix = token_bridge.register_chain_ix(token_bridge_id.toString(), bridge_id.toString(), from.publicKey.toString(), vaa);
|
||||
break
|
||||
case 2:
|
||||
console.log("Upgrading contract")
|
||||
ix = token_bridge.upgrade_contract_ix(token_bridge_id.toString(), bridge_id.toString(), from.publicKey.toString(), from.publicKey.toString(), vaa);
|
||||
break
|
||||
default:
|
||||
throw new Error("unknown governance action")
|
||||
}
|
||||
let transaction = new web3s.Transaction().add(ixFromRust(ix));
|
||||
|
||||
// Sign transaction, broadcast, and confirm
|
||||
let signature = await web3s.sendAndConfirmTransaction(
|
||||
connection,
|
||||
transaction,
|
||||
[from],
|
||||
{
|
||||
skipPreflight: true
|
||||
}
|
||||
);
|
||||
console.log('SIGNATURE', signature);
|
||||
})
|
||||
.command('eth execute_governance_vaa [vaa]', 'execute a governance VAA on evm', (yargs) => {
|
||||
return yargs
|
||||
.positional('vaa', {
|
||||
describe: 'vaa to post',
|
||||
type: "string",
|
||||
required: true
|
||||
})
|
||||
.option('rpc', {
|
||||
alias: 'u',
|
||||
type: 'string',
|
||||
description: 'URL of the ETH RPC',
|
||||
default: "http://localhost:8545"
|
||||
})
|
||||
.option('token_bridge', {
|
||||
alias: 't',
|
||||
type: 'string',
|
||||
description: 'Token Bridge address',
|
||||
default: "0x0290FB167208Af455bB137780163b7B7a9a10C16"
|
||||
})
|
||||
.option('key', {
|
||||
alias: 'k',
|
||||
type: 'string',
|
||||
description: 'Private key of the wallet',
|
||||
default: "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d"
|
||||
})
|
||||
}, async (argv) => {
|
||||
const bridge = await importCoreWasm()
|
||||
|
||||
let provider = new ethers.providers.JsonRpcProvider(argv.rpc)
|
||||
let signer = new ethers.Wallet(argv.key, provider)
|
||||
let t = new BridgeImplementation__factory(signer);
|
||||
let tb = t.attach(argv.token_bridge);
|
||||
|
||||
let vaa = Buffer.from(String(argv.vaa), "hex");
|
||||
let parsed_vaa = await bridge.parse_vaa(vaa);
|
||||
|
||||
switch (parsed_vaa.payload[32]) {
|
||||
case 1:
|
||||
console.log("Registering chain")
|
||||
console.log("Hash: " + (await tb.registerChain(vaa)).hash)
|
||||
break
|
||||
case 2:
|
||||
console.log("Upgrading contract")
|
||||
console.log("Hash: " + (await tb.upgrade(vaa)).hash)
|
||||
console.log("Don't forget to verify the new implementation! See ethereum/VERIFY.md for instructions")
|
||||
break
|
||||
default:
|
||||
throw new Error("unknown governance action")
|
||||
}
|
||||
})
|
||||
.argv;
|
||||
|
||||
async function post_vaa(connection: Connection, bridge_id: PublicKey, payer: Keypair, vaa: Buffer) {
|
||||
const bridge = await importCoreWasm()
|
||||
|
||||
let bridge_state = await get_bridge_state(connection, bridge_id);
|
||||
let guardian_addr = new PublicKey(bridge.guardian_set_address(bridge_id.toString(), bridge_state.guardian_set_index));
|
||||
let acc = await connection.getAccountInfo(guardian_addr);
|
||||
if (acc?.data === undefined) {
|
||||
return
|
||||
}
|
||||
let guardian_data = bridge.parse_guardian_set(new Uint8Array(acc?.data));
|
||||
|
||||
let signature_set = Keypair.generate();
|
||||
let txs = bridge.verify_signatures_ix(bridge_id.toString(), payer.publicKey.toString(), bridge_state.guardian_set_index, guardian_data, signature_set.publicKey.toString(), vaa)
|
||||
// Add transfer instruction to transaction
|
||||
for (let tx of txs) {
|
||||
let ixs: Array<TransactionInstruction> = tx.map((v: any) => {
|
||||
return ixFromRust(v)
|
||||
})
|
||||
let transaction = new web3s.Transaction().add(ixs[0], ixs[1]);
|
||||
|
||||
// Sign transaction, broadcast, and confirm
|
||||
await web3s.sendAndConfirmTransaction(
|
||||
connection,
|
||||
transaction,
|
||||
[payer, signature_set],
|
||||
{
|
||||
skipPreflight: true
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
let ix = ixFromRust(bridge.post_vaa_ix(bridge_id.toString(), payer.publicKey.toString(), signature_set.publicKey.toString(), vaa));
|
||||
let transaction = new web3s.Transaction().add(ix);
|
||||
|
||||
// Sign transaction, broadcast, and confirm
|
||||
let signature = await web3s.sendAndConfirmTransaction(
|
||||
connection,
|
||||
transaction,
|
||||
[payer],
|
||||
{
|
||||
skipPreflight: true
|
||||
}
|
||||
);
|
||||
console.log('SIGNATURE', signature);
|
||||
}
|
||||
|
||||
async function get_bridge_state(connection: Connection, bridge_id: PublicKey): Promise<BridgeState> {
|
||||
const bridge = await importCoreWasm()
|
||||
|
||||
let bridge_state = new PublicKey(bridge.state_address(bridge_id.toString()));
|
||||
let acc = await connection.getAccountInfo(bridge_state);
|
||||
if (acc?.data === undefined) {
|
||||
throw new Error("bridge state not found")
|
||||
}
|
||||
return bridge.parse_state(new Uint8Array(acc?.data));
|
||||
}
|
||||
|
||||
function setupConnection(argv: yargs.Arguments): web3s.Connection {
|
||||
return new web3s.Connection(
|
||||
argv.rpc as string,
|
||||
'confirmed',
|
||||
);
|
||||
}
|
||||
|
||||
function fmtAddress(addr: string): string {
|
||||
let address = (addr.search("0x") == 0) ? addr.substring(2) : addr;
|
||||
return "0x" + zeroPadBytes(address, 32);
|
||||
}
|
||||
|
||||
interface BridgeState {
|
||||
// The current guardian set index, used to decide which signature sets to accept.
|
||||
guardian_set_index: number,
|
||||
|
||||
// Lamports in the collection account
|
||||
last_lamports: number,
|
||||
|
||||
// Bridge configuration, which is set once upon initialization.
|
||||
config: BridgeConfig,
|
||||
}
|
||||
|
||||
interface BridgeConfig {
|
||||
// Period for how long a guardian set is valid after it has been replaced by a new one. This
|
||||
// guarantees that VAAs issued by that set can still be submitted for a certain period. In
|
||||
// this period we still trust the old guardian set.
|
||||
guardian_set_expiration_time: number,
|
||||
|
||||
// Amount of lamports that needs to be paid to the protocol to post a message
|
||||
fee: number,
|
||||
}
|
|
@ -1,72 +0,0 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
/* Visit https://aka.ms/tsconfig.json to read more about this file */
|
||||
|
||||
/* Basic Options */
|
||||
// "incremental": true, /* Enable incremental compilation */
|
||||
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */
|
||||
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
|
||||
// "lib": [], /* Specify library files to be included in the compilation. */
|
||||
// "allowJs": true, /* Allow javascript files to be compiled. */
|
||||
// "checkJs": true, /* Report errors in .js files. */
|
||||
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */
|
||||
// "declaration": true, /* Generates corresponding '.d.ts' file. */
|
||||
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
||||
// "sourceMap": true, /* Generates corresponding '.map' file. */
|
||||
// "outFile": "./", /* Concatenate and emit output to single file. */
|
||||
// "outDir": "./", /* Redirect output structure to the directory. */
|
||||
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
||||
// "composite": true, /* Enable project compilation */
|
||||
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
|
||||
// "removeComments": true, /* Do not emit comments to output. */
|
||||
// "noEmit": true, /* Do not emit outputs. */
|
||||
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
|
||||
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
|
||||
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
|
||||
|
||||
/* Strict Type-Checking Options */
|
||||
"strict": true, /* Enable all strict type-checking options. */
|
||||
"noImplicitAny": false, /* Raise error on expressions and declarations with an implied 'any' type. */
|
||||
// "strictNullChecks": true, /* Enable strict null checks. */
|
||||
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
|
||||
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
|
||||
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
|
||||
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
|
||||
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
|
||||
|
||||
/* Additional Checks */
|
||||
// "noUnusedLocals": true, /* Report errors on unused locals. */
|
||||
// "noUnusedParameters": true, /* Report errors on unused parameters. */
|
||||
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
|
||||
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
||||
// "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
|
||||
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an 'override' modifier. */
|
||||
// "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */
|
||||
|
||||
/* Module Resolution Options */
|
||||
"moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
|
||||
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
|
||||
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
||||
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
||||
// "typeRoots": [], /* List of folders to include type definitions from. */
|
||||
// "types": [], /* Type declaration files to be included in compilation. */
|
||||
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
|
||||
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
||||
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
|
||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||
|
||||
/* Source Map Options */
|
||||
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
|
||||
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
|
||||
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
|
||||
|
||||
/* Experimental Options */
|
||||
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
|
||||
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
|
||||
|
||||
/* Advanced Options */
|
||||
"skipLibCheck": true, /* Skip type checking of declaration files. */
|
||||
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
|
||||
}
|
||||
}
|
|
@ -85,28 +85,23 @@ terraNFTBridge=$(jq --raw-output '.chains."3".contracts.nftBridgeEmitterAddress'
|
|||
# 4) create token bridge registration VAAs
|
||||
echo "generating contract registration VAAs for token bridges"
|
||||
# fetch dependencies for the clients/token_bridge script that generates token bridge registration VAAs
|
||||
if [[ ! -d ./clients/token_bridge/node_modules ]]; then
|
||||
echo "going to install node modules in clients/token_bridge"
|
||||
npm ci --prefix clients/token_bridge && npm run build --prefix clients/token_bridge
|
||||
if [[ ! -d ./clients/js/node_modules ]]; then
|
||||
echo "going to install node modules in clients/js"
|
||||
npm ci --prefix clients/js
|
||||
fi
|
||||
# invoke clients/token_bridge commands to create registration VAAs
|
||||
solTokenBridgeVAA=$(npm --prefix clients/token_bridge run --silent main -- generate_register_chain_vaa 1 0x${solTokenBridge} --guardian_secret ${guardiansPrivateCSV})
|
||||
ethTokenBridgeVAA=$(npm --prefix clients/token_bridge run --silent main -- generate_register_chain_vaa 2 0x${ethTokenBridge} --guardian_secret ${guardiansPrivateCSV} )
|
||||
terraTokenBridgeVAA=$(npm --prefix clients/token_bridge run --silent main -- generate_register_chain_vaa 3 0x${terraTokenBridge} --guardian_secret ${guardiansPrivateCSV})
|
||||
bscTokenBridgeVAA=$(npm --prefix clients/token_bridge run --silent main -- generate_register_chain_vaa 4 0x${bscTokenBridge} --guardian_secret ${guardiansPrivateCSV})
|
||||
algoTokenBridgeVAA=$(npm --prefix clients/token_bridge run --silent main -- generate_register_chain_vaa 8 0x${algoTokenBridge} --guardian_secret ${guardiansPrivateCSV})
|
||||
solTokenBridgeVAA=$(npm --prefix clients/js start --silent -- generate registration -m TokenBridge -c solana -a ${solTokenBridge} -g ${guardiansPrivateCSV})
|
||||
ethTokenBridgeVAA=$(npm --prefix clients/js start --silent -- generate registration -m TokenBridge -c ethereum -a ${ethTokenBridge} -g ${guardiansPrivateCSV} )
|
||||
terraTokenBridgeVAA=$(npm --prefix clients/js start --silent -- generate registration -m TokenBridge -c terra -a ${terraTokenBridge} -g ${guardiansPrivateCSV})
|
||||
bscTokenBridgeVAA=$(npm --prefix clients/js start --silent -- generate registration -m TokenBridge -c bsc -a ${bscTokenBridge} -g ${guardiansPrivateCSV})
|
||||
algoTokenBridgeVAA=$(npm --prefix clients/js start --silent -- generate registration -m TokenBridge -c algorand -a ${algoTokenBridge} -g ${guardiansPrivateCSV})
|
||||
|
||||
|
||||
# 5) create nft bridge registration VAAs
|
||||
# fetch dependencies for the clients/nft_bridge script that generates nft bridge registration VAAs
|
||||
if [[ ! -d ./clients/nft_bridge/node_modules ]]; then
|
||||
echo "going to install node modules in clients/nft_bridge"
|
||||
npm ci --prefix clients/nft_bridge && npm run build --prefix clients/nft_bridge
|
||||
fi
|
||||
echo "generating contract registration VAAs for nft bridges"
|
||||
solNFTBridgeVAA=$(npm --prefix clients/nft_bridge run --silent main -- generate_register_chain_vaa 1 0x${solNFTBridge} --guardian_secret ${guardiansPrivateCSV})
|
||||
ethNFTBridgeVAA=$(npm --prefix clients/nft_bridge run --silent main -- generate_register_chain_vaa 2 0x${ethNFTBridge} --guardian_secret ${guardiansPrivateCSV})
|
||||
terraNFTBridgeVAA=$(npm --prefix clients/nft_bridge run --silent main -- generate_register_chain_vaa 3 0x${terraNFTBridge} --guardian_secret ${guardiansPrivateCSV})
|
||||
solNFTBridgeVAA=$(npm --prefix clients/js start --silent -- generate registration -m NFTBridge -c solana -a ${solNFTBridge} -g ${guardiansPrivateCSV})
|
||||
ethNFTBridgeVAA=$(npm --prefix clients/js start --silent -- generate registration -m NFTBridge -c ethereum -a ${ethNFTBridge} -g ${guardiansPrivateCSV})
|
||||
terraNFTBridgeVAA=$(npm --prefix clients/js start --silent -- generate registration -m NFTBridge -c terra -a ${terraNFTBridge} -g ${guardiansPrivateCSV})
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -93,18 +93,15 @@ retry token-bridge-client create-bridge "$token_bridge_address" "$bridge_address
|
|||
retry token-bridge-client create-bridge "$nft_bridge_address" "$bridge_address"
|
||||
|
||||
# pass the chain registration VAAs sourced from .env to the client's execute-governance command:
|
||||
pushd /usr/src/clients/token_bridge
|
||||
pushd /usr/src/clients/js
|
||||
# Register the Token Bridge Endpoint on ETH
|
||||
node main.js solana execute_governance_vaa "$REGISTER_ETH_TOKEN_BRIDGE_VAA"
|
||||
node main.js solana execute_governance_vaa "$REGISTER_TERRA_TOKEN_BRIDGE_VAA"
|
||||
node main.js solana execute_governance_vaa "$REGISTER_BSC_TOKEN_BRIDGE_VAA"
|
||||
node main.js solana execute_governance_vaa "$REGISTER_ALGO_TOKEN_BRIDGE_VAA"
|
||||
popd
|
||||
|
||||
pushd /usr/src/clients/nft_bridge
|
||||
npm start -- submit -c solana -n devnet "$REGISTER_ETH_TOKEN_BRIDGE_VAA"
|
||||
npm start -- submit -c solana -n devnet "$REGISTER_TERRA_TOKEN_BRIDGE_VAA"
|
||||
npm start -- submit -c solana -n devnet "$REGISTER_BSC_TOKEN_BRIDGE_VAA"
|
||||
npm start -- submit -c solana -n devnet "$REGISTER_ALGO_TOKEN_BRIDGE_VAA"
|
||||
# Register the NFT Bridge Endpoint on ETH
|
||||
node main.js solana execute_governance_vaa "$REGISTER_ETH_NFT_BRIDGE_VAA"
|
||||
node main.js solana execute_governance_vaa "$REGISTER_TERRA_NFT_BRIDGE_VAA"
|
||||
npm start -- submit -c solana -n devnet "$REGISTER_ETH_NFT_BRIDGE_VAA"
|
||||
npm start -- submit -c solana -n devnet "$REGISTER_TERRA_NFT_BRIDGE_VAA"
|
||||
popd
|
||||
|
||||
# Let k8s startup probe succeed
|
||||
|
|
Loading…
Reference in New Issue