| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266 |
- import { LCDClient, MnemonicKey } from "@terra-money/terra.js";
- import {
- MsgInstantiateContract,
- MsgMigrateContract,
- MsgStoreCode,
- } from "@terra-money/terra.js";
- import { readFileSync } from "fs";
- import { Bech32, toHex } from "@cosmjs/encoding";
- import { zeroPad } from "ethers/lib/utils.js";
- import axios from "axios";
- import yargs from "yargs";
- import { hideBin } from "yargs/helpers";
- import assert from "assert";
- export const TERRA_GAS_PRICES_URL = "https://fcd.terra.dev/v1/txs/gas_prices";
- const argv = yargs(hideBin(process.argv))
- .option("network", {
- description: "Which network to deploy to",
- choices: ["mainnet", "testnet"],
- required: true,
- })
- .option("artifact", {
- description: "Path to Pyth artifact",
- type: "string",
- required: false,
- })
- .option("mnemonic", {
- description: "Mnemonic (private key)",
- type: "string",
- required: true,
- })
- .option("instantiate", {
- description: "Instantiate contract if set (default: disabled)",
- type: "boolean",
- default: false,
- required: false,
- })
- .option("migrate", {
- description: "Migrate an existing contract if set (default: disabled)",
- type: "boolean",
- default: false,
- required: false,
- })
- .option("contract", {
- description: "Contract address, used only for migration",
- type: "string",
- required: false,
- default: "",
- })
- .option("code-id", {
- description:
- "Code Id, if provided this will be used for migrate/instantiate and no code will be uploaded",
- type: "number",
- requred: false,
- })
- .help()
- .alias("help", "h").argv;
- const artifact = argv.artifact;
- /* Set up terra client & wallet. It won't fail because inputs are validated with yargs */
- const CONFIG = {
- mainnet: {
- terraHost: {
- URL: "https://phoenix-lcd.terra.dev",
- chainID: "phoenix-1",
- name: "mainnet",
- },
- wormholeContract:
- "terra12mrnzvhx3rpej6843uge2yyfppfyd3u9c3uq223q8sl48huz9juqffcnh",
- pythEmitterAddress:
- "6bb14509a612f01fbbc4cffeebd4bbfb492a86df717ebe92eb6df432a3f00a25",
- },
- testnet: {
- terraHost: {
- URL: "https://pisco-lcd.terra.dev",
- chainID: "pisco-1",
- name: "testnet",
- },
- wormholeContract:
- "terra19nv3xr5lrmmr7egvrk2kqgw4kcn43xrtd5g0mpgwwvhetusk4k7s66jyv0",
- pythEmitterAddress:
- "f346195ac02f37d60d4db8ffa6ef74cb1be3550047543a4a9ee9acf4d78697b0",
- },
- };
- const terraHost = CONFIG[argv.network].terraHost;
- const wormholeContract = CONFIG[argv.network].wormholeContract;
- const pythEmitterAddress = CONFIG[argv.network].pythEmitterAddress;
- const lcd = new LCDClient(terraHost);
- const feeDenoms = ["uluna"];
- const gasPrices = await axios
- .get(TERRA_GAS_PRICES_URL)
- .then((result) => result.data);
- const wallet = lcd.wallet(
- new MnemonicKey({
- mnemonic: argv.mnemonic,
- })
- );
- /* Deploy artifacts */
- var codeId;
- if (argv.codeId !== undefined) {
- codeId = argv.codeId;
- } else {
- if (argv.artifact === undefined) {
- console.error(
- "Artifact is not provided. Please at least provide artifact or code id"
- );
- process.exit(1);
- }
- const contract_bytes = readFileSync(artifact);
- console.log(`Storing WASM: ${artifact} (${contract_bytes.length} bytes)`);
- const store_code = new MsgStoreCode(
- wallet.key.accAddress,
- contract_bytes.toString("base64")
- );
- /*
- const feeEstimate = await lcd.tx.estimateFee([wallet.key.accAddress], {
- msgs: [store_code],
- feeDenoms,
- // gasPrices,
- });
- */
- console.log("Deploy fee: ", feeEstimate.amount.toString());
- const tx = await wallet.createAndSignTx({
- msgs: [store_code],
- feeDenoms,
- // gasPrices,
- // fee: feeEstimate,
- });
- const rs = await lcd.tx.broadcast(tx);
- try {
- const ci = /"code_id","value":"([^"]+)/gm.exec(rs.raw_log)[1];
- codeId = parseInt(ci);
- } catch (e) {
- console.error(
- "Encountered an error in parsing deploy code result. Printing raw log"
- );
- console.error(rs.raw_log);
- throw e;
- }
- console.log("Code ID: ", codeId);
- if (argv.instantiate || argv.migrate) {
- console.log("Sleeping for 10 seconds for store transaction to finalize.");
- await sleep(10000);
- }
- }
- if (argv.instantiate) {
- console.log("Instantiating a contract");
- async function instantiate(codeId, inst_msg) {
- var address;
- await wallet
- .createAndSignTx({
- msgs: [
- new MsgInstantiateContract(
- wallet.key.accAddress,
- wallet.key.accAddress,
- codeId,
- inst_msg
- ),
- ],
- })
- .then((tx) => lcd.tx.broadcast(tx))
- .then((rs) => {
- try {
- address = /"contract_address","value":"([^"]+)/gm.exec(rs.raw_log)[1];
- } catch (e) {
- console.error(
- "Encountered an error in parsing instantiation result. Printing raw log"
- );
- console.error(rs.raw_log);
- throw e;
- }
- });
- console.log(
- `Instantiated Pyth at ${address} (${convert_terra_address_to_hex(
- address
- )})`
- );
- return address;
- }
- const pythChain = 1;
- const contractAddress = await instantiate(codeId, {
- wormhole_contract: wormholeContract,
- pyth_emitter: Buffer.from(pythEmitterAddress, "hex").toString("base64"),
- pyth_emitter_chain: pythChain,
- });
- console.log(`Deployed Pyth contract at ${contractAddress}`);
- }
- if (argv.migrate) {
- if (argv.contract === "") {
- console.error(
- "Contract address is not provided. Provide it using --contract"
- );
- process.exit(1);
- }
- console.log(`Migrating contract ${argv.contract} to ${codeId}`);
- const tx = await wallet.createAndSignTx({
- msgs: [
- new MsgMigrateContract(
- wallet.key.accAddress,
- argv.contract,
- codeId,
- {
- action: "",
- },
- { uluna: 1000 }
- ),
- ],
- feeDenoms,
- // gasPrices,
- });
- const rs = await lcd.tx.broadcast(tx);
- var resultCodeId;
- try {
- resultCodeId = /"code_id","value":"([^"]+)/gm.exec(rs.raw_log)[1];
- assert.equal(codeId, resultCodeId);
- } catch (e) {
- console.error(
- "Encountered an error in parsing migration result. Printing raw log"
- );
- console.error(rs.raw_log);
- throw e;
- }
- console.log(
- `Contract ${argv.contract} code_id successfully updated to ${resultCodeId}`
- );
- }
- // Terra addresses are "human-readable", but for cross-chain registrations, we
- // want the "canonical" version
- function convert_terra_address_to_hex(human_addr) {
- return "0x" + toHex(zeroPad(Bech32.decode(human_addr).data, 32));
- }
- function sleep(ms) {
- return new Promise((resolve) => setTimeout(resolve, ms));
- }
|