pyth-crosschain/target-chains/cosmwasm/tools/deploy-pyth-bridge.js

303 lines
7.4 KiB
JavaScript

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 yargs from "yargs";
import { hideBin } from "yargs/helpers";
import assert from "assert";
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",
},
pyth_config: {
wormhole_contract:
"terra12mrnzvhx3rpej6843uge2yyfppfyd3u9c3uq223q8sl48huz9juqffcnh",
data_sources: [
{
emitter: Buffer.from(
"6bb14509a612f01fbbc4cffeebd4bbfb492a86df717ebe92eb6df432a3f00a25",
"hex"
).toString("base64"),
chain_id: 1,
},
{
emitter: Buffer.from(
"f8cd23c2ab91237730770bbea08d61005cdda0984348f3f6eecb559638c0bba0",
"hex"
).toString("base64"),
chain_id: 26,
},
],
governance_source: {
emitter: Buffer.from(
"5635979a221c34931e32620b9293a463065555ea71fe97cd6237ade875b12e9e",
"hex"
).toString("base64"),
chain_id: 1,
},
governance_source_index: 0,
governance_sequence_number: 0,
chain_id: 18,
valid_time_period_secs: 60,
fee: {
amount: "1",
denom: "uluna",
},
},
},
testnet: {
terraHost: {
URL: "https://pisco-lcd.terra.dev",
chainID: "pisco-1",
name: "testnet",
},
pyth_config: {
wormhole_contract:
"terra19nv3xr5lrmmr7egvrk2kqgw4kcn43xrtd5g0mpgwwvhetusk4k7s66jyv0",
data_sources: [
{
emitter: Buffer.from(
"f346195ac02f37d60d4db8ffa6ef74cb1be3550047543a4a9ee9acf4d78697b0",
"hex"
).toString("base64"),
chain_id: 1,
},
{
emitter: Buffer.from(
"a27839d641b07743c0cb5f68c51f8cd31d2c0762bec00dc6fcd25433ef1ab5b6",
"hex"
).toString("base64"),
chain_id: 26,
},
],
governance_source: {
emitter: Buffer.from(
"63278d271099bfd491951b3e648f08b1c71631e4a53674ad43e8f9f98068c385",
"hex"
).toString("base64"),
chain_id: 1,
},
governance_source_index: 0,
governance_sequence_number: 0,
chain_id: 18,
valid_time_period_secs: 60,
fee: {
amount: "1",
denom: "uluna",
},
},
},
};
const terraHost = CONFIG[argv.network].terraHost;
const pythConfig = CONFIG[argv.network].pyth_config;
const lcd = new LCDClient(terraHost);
const feeDenoms = ["uluna"];
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 tx = await wallet.createAndSignTx({
msgs: [store_code],
feeDenoms,
});
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, label) {
var address;
await wallet
.createAndSignTx({
msgs: [
new MsgInstantiateContract(
wallet.key.accAddress,
wallet.key.accAddress,
codeId,
inst_msg,
undefined,
label
),
],
})
.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 contractAddress = await instantiate(codeId, pythConfig, "pyth");
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,
});
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));
}