Injective deployment code (#465)
* make it all typescript * what the hell * injective - store, instantiate, and migrate works * terra, injective refactored * update compiler in build.sh * update package.json * deploy.ts * pre-commit run * replace helper functions call with actual call * correct case of RaiseCLError * update deployer factory to take in config * add comment to gas for injective store code * extract raw log logic * remove comment from injective config * update deploy script for tilt Co-authored-by: Jayant Krishnamurthy <jkrishnamurthy@jumptrading.com>
This commit is contained in:
parent
2a961d5853
commit
627edaa62a
|
@ -27,7 +27,7 @@ Then, to deploy the Pyth contract (`pyth_cosmwasm.wasm`), run the following comm
|
|||
|
||||
```sh
|
||||
npm ci # Do it only once to install the required packages
|
||||
npm run deploy-pyth -- --network testnet --artifact ../artifacts/pyth_cosmwasm.wasm --mnemonic "..."
|
||||
npm run deploy-pyth -- --network terra_testnet --artifact ../artifacts/pyth_cosmwasm.wasm --mnemonic "..."
|
||||
```
|
||||
|
||||
If successful, this command will print something along the lines of:
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
docker run --rm -v "$(pwd)":/code \
|
||||
-v $(cd ../third_party; pwd):/third_party \
|
||||
-v $(cd ../../third_party; pwd):/third_party \
|
||||
--mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \
|
||||
--mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \
|
||||
cosmwasm/workspace-optimizer:0.12.5
|
||||
cosmwasm/workspace-optimizer:0.12.6
|
||||
|
|
|
@ -1,302 +0,0 @@
|
|||
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));
|
||||
}
|
|
@ -1,204 +0,0 @@
|
|||
// Deploy Wormhole and Pyth contract to Tilt. If you want to
|
||||
// test the contracts locally you need to build the wormhole contract
|
||||
// as well. You can use Dockerfile.cosmwasm in the root of this repo
|
||||
// to do that.
|
||||
|
||||
import { LCDClient, MnemonicKey } from "@terra-money/terra.js";
|
||||
import { MsgInstantiateContract, MsgStoreCode } from "@terra-money/terra.js";
|
||||
import { readFileSync, readdirSync } from "fs";
|
||||
import { Bech32, toHex } from "@cosmjs/encoding";
|
||||
import { zeroPad } from "ethers/lib/utils.js";
|
||||
|
||||
/*
|
||||
NOTE: Only append to this array: keeping the ordering is crucial, as the
|
||||
contracts must be imported in a deterministic order so their addresses remain
|
||||
deterministic.
|
||||
*/
|
||||
const artifacts = ["wormhole.wasm", "pyth_cosmwasm.wasm"];
|
||||
|
||||
/* Check that the artifact folder contains all the wasm files we expect and nothing else */
|
||||
|
||||
const actual_artifacts = readdirSync("../artifacts/").filter((a) =>
|
||||
a.endsWith(".wasm")
|
||||
);
|
||||
|
||||
const missing_artifacts = artifacts.filter(
|
||||
(a) => !actual_artifacts.includes(a)
|
||||
);
|
||||
if (missing_artifacts.length) {
|
||||
console.log(
|
||||
"Error during terra deployment. The following files are expected to be in the artifacts folder:"
|
||||
);
|
||||
missing_artifacts.forEach((file) => console.log(` - ${file}`));
|
||||
console.log(
|
||||
"Hint: the deploy script needs to run after the contracts have been built."
|
||||
);
|
||||
console.log(
|
||||
"External binary blobs need to be manually added in tools/Dockerfile."
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const unexpected_artifacts = actual_artifacts.filter(
|
||||
(a) => !artifacts.includes(a)
|
||||
);
|
||||
if (unexpected_artifacts.length) {
|
||||
console.log(
|
||||
"Error during terra deployment. The following files are not expected to be in the artifacts folder:"
|
||||
);
|
||||
unexpected_artifacts.forEach((file) => console.log(` - ${file}`));
|
||||
console.log("Hint: you might need to modify tools/deploy.js");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
/* Set up terra client & wallet */
|
||||
|
||||
const terra = new LCDClient({
|
||||
URL: "http://localhost:1317",
|
||||
chainID: "localterra",
|
||||
});
|
||||
|
||||
const wallet = terra.wallet(
|
||||
new MnemonicKey({
|
||||
mnemonic:
|
||||
"notice oak worry limit wrap speak medal online prefer cluster roof addict wrist behave treat actual wasp year salad speed social layer crew genius",
|
||||
})
|
||||
);
|
||||
|
||||
await wallet.sequence();
|
||||
|
||||
/* Deploy artifacts */
|
||||
|
||||
const codeIds = {};
|
||||
for (const file of artifacts) {
|
||||
const contract_bytes = readFileSync(`../artifacts/${file}`);
|
||||
console.log(`Storing WASM: ${file} (${contract_bytes.length} bytes)`);
|
||||
|
||||
const store_code = new MsgStoreCode(
|
||||
wallet.key.accAddress,
|
||||
contract_bytes.toString("base64")
|
||||
);
|
||||
|
||||
try {
|
||||
const tx = await wallet.createAndSignTx({
|
||||
msgs: [store_code],
|
||||
memo: "",
|
||||
});
|
||||
|
||||
const rs = await terra.tx.broadcast(tx);
|
||||
const ci = /"code_id","value":"([^"]+)/gm.exec(rs.raw_log)[1];
|
||||
codeIds[file] = parseInt(ci);
|
||||
} catch (e) {
|
||||
console.log(`${e}`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(codeIds);
|
||||
|
||||
/* Instantiate contracts.
|
||||
*
|
||||
* We instantiate the core contracts here (i.e. wormhole itself and the bridge contracts).
|
||||
* The wrapped asset contracts don't need to be instantiated here, because those
|
||||
* will be instantiated by the on-chain bridge contracts on demand.
|
||||
* */
|
||||
|
||||
// Governance constants defined by the Wormhole spec.
|
||||
const govChain = 1;
|
||||
const govAddress =
|
||||
"0000000000000000000000000000000000000000000000000000000000000004";
|
||||
|
||||
async function instantiate(contract, inst_msg, label) {
|
||||
var address;
|
||||
await wallet
|
||||
.createAndSignTx({
|
||||
msgs: [
|
||||
new MsgInstantiateContract(
|
||||
wallet.key.accAddress,
|
||||
wallet.key.accAddress,
|
||||
codeIds[contract],
|
||||
inst_msg,
|
||||
undefined,
|
||||
label
|
||||
),
|
||||
],
|
||||
memo: "",
|
||||
})
|
||||
.then((tx) => terra.tx.broadcast(tx))
|
||||
.then((rs) => {
|
||||
address = /"_contract_address","value":"([^"]+)/gm.exec(rs.raw_log)[1];
|
||||
});
|
||||
console.log(
|
||||
`Instantiated ${contract} at ${address} (${convert_terra_address_to_hex(
|
||||
address
|
||||
)})`
|
||||
);
|
||||
return address;
|
||||
}
|
||||
|
||||
// Instantiate contracts. NOTE: Only append at the end, the ordering must be
|
||||
// deterministic for the addresses to work
|
||||
|
||||
const addresses = {};
|
||||
|
||||
addresses["wormhole.wasm"] = await instantiate(
|
||||
"wormhole.wasm",
|
||||
{
|
||||
gov_chain: govChain,
|
||||
gov_address: Buffer.from(govAddress, "hex").toString("base64"),
|
||||
guardian_set_expirity: 86400,
|
||||
initial_guardian_set: {
|
||||
addresses: [
|
||||
{
|
||||
bytes: Buffer.from(
|
||||
"beFA429d57cD18b7F8A4d91A2da9AB4AF05d0FBe",
|
||||
"hex"
|
||||
).toString("base64"),
|
||||
},
|
||||
],
|
||||
expiration_time: 0,
|
||||
},
|
||||
chain_id: 18,
|
||||
fee_denom: "uluna",
|
||||
},
|
||||
"wormhole"
|
||||
);
|
||||
|
||||
const pythEmitterAddress =
|
||||
"71f8dcb863d176e2c420ad6610cf687359612b6fb392e0642b0ca6b1f186aa3b";
|
||||
const pythGovernanceEmitterAddress =
|
||||
"0000000000000000000000000000000000000000000000000000000000001234";
|
||||
const pythChain = 1;
|
||||
|
||||
addresses["pyth_cosmwasm.wasm"] = await instantiate(
|
||||
"pyth_cosmwasm.wasm",
|
||||
{
|
||||
wormhole_contract: addresses["wormhole.wasm"],
|
||||
data_sources: [
|
||||
{
|
||||
emitter: Buffer.from(pythEmitterAddress, "hex").toString("base64"),
|
||||
chain_id: pythChain,
|
||||
},
|
||||
],
|
||||
governance_source: {
|
||||
emitter: Buffer.from(pythGovernanceEmitterAddress, "hex").toString(
|
||||
"base64"
|
||||
),
|
||||
chain_id: pythChain,
|
||||
},
|
||||
governance_source_index: 0,
|
||||
governance_sequence_number: 0,
|
||||
chain_id: 3,
|
||||
valid_time_period_secs: 60,
|
||||
fee: {
|
||||
amount: "1",
|
||||
denom: "uluna",
|
||||
},
|
||||
},
|
||||
"pyth"
|
||||
);
|
||||
|
||||
// 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));
|
||||
}
|
|
@ -10,4 +10,4 @@ done
|
|||
|
||||
sleep 2
|
||||
|
||||
node deploy.js
|
||||
npm run deploy
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -2,18 +2,31 @@
|
|||
"name": "tools",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "deploy.js",
|
||||
"type": "module",
|
||||
"main": "deploy-pyth-bridge.ts",
|
||||
"scripts": {
|
||||
"deploy-pyth": "node deploy-pyth-bridge.js"
|
||||
"build": "tsc",
|
||||
"deploy-pyth": "ts-node ./src/deploy-pyth-bridge.ts",
|
||||
"deploy": "ts-node ./src/deploy.ts"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@cosmjs/encoding": "^0.26.2",
|
||||
"@injectivelabs/networks": "^1.0.55",
|
||||
"@injectivelabs/sdk-ts": "^1.0.330",
|
||||
"@injectivelabs/utils": "^1.0.47",
|
||||
"@terra-money/terra.js": "^3.1.3",
|
||||
"dotenv": "^16.0.0",
|
||||
"ethers": "^5.4.4",
|
||||
"yargs": "^17.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/yargs": "^17.0.18",
|
||||
"@typescript-eslint/eslint-plugin": "^5.43.0",
|
||||
"@typescript-eslint/parser": "^5.43.0",
|
||||
"eslint": "^8.27.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^4.9.3"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
import yargs from "yargs";
|
||||
import { hideBin } from "yargs/helpers";
|
||||
import { Deployer, DeployerFactory } from "./deployer";
|
||||
import { NETWORKS_OPTIONS } from "./network";
|
||||
import { CONFIG as PythConfig } from "./pyth_config";
|
||||
import { CONFIG as NetworkConfig } from "./deployer/config";
|
||||
|
||||
const argv = yargs(hideBin(process.argv))
|
||||
.option("network", {
|
||||
description: "Which network to deploy to",
|
||||
choices: NETWORKS_OPTIONS,
|
||||
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")
|
||||
.parseSync();
|
||||
|
||||
const {
|
||||
artifact,
|
||||
network,
|
||||
mnemonic,
|
||||
codeId: inputCodeId,
|
||||
instantiate,
|
||||
migrate,
|
||||
contract,
|
||||
} = argv;
|
||||
const pythConfig = PythConfig[network];
|
||||
const networkConfig = NetworkConfig[network];
|
||||
const deployer: Deployer = DeployerFactory.create(networkConfig, mnemonic);
|
||||
|
||||
// checks
|
||||
if (inputCodeId === undefined && artifact === undefined)
|
||||
raiseCLError("Please provide either artifact or code id");
|
||||
|
||||
function sleep(ms: number) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
function raiseCLError(message: string) {
|
||||
console.error(message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
async function run() {
|
||||
let codeId: number;
|
||||
if (inputCodeId === undefined) {
|
||||
console.log("Deploying artifact");
|
||||
codeId = await deployer.deployArtifact(artifact!);
|
||||
console.log("Deployed Code ID: ", codeId);
|
||||
|
||||
// sleep only when a new artifact is deployed
|
||||
if (instantiate || migrate) {
|
||||
console.log("Sleeping for 10 seconds for store transaction to finalize.");
|
||||
await sleep(10000);
|
||||
}
|
||||
} else codeId = inputCodeId;
|
||||
|
||||
if (instantiate) {
|
||||
console.log("Instantiating a contract");
|
||||
const contractAddress = await deployer.instantiate(
|
||||
codeId,
|
||||
pythConfig,
|
||||
"pyth"
|
||||
);
|
||||
console.log(`Deployed Pyth contract at ${contractAddress}`);
|
||||
}
|
||||
if (migrate) {
|
||||
if (contract === "")
|
||||
raiseCLError(
|
||||
"Contract address is not provided. Provide it using --contract"
|
||||
);
|
||||
|
||||
console.log(`Migrating contract ${contract} to ${codeId}`);
|
||||
await deployer.migrate(contract, codeId);
|
||||
console.log(
|
||||
`Contract ${contract} code_id successfully updated to ${codeId}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
run();
|
|
@ -0,0 +1,161 @@
|
|||
// Deploy Wormhole and Pyth contract to Tilt. If you want to
|
||||
// test the contracts locally you need to build the wormhole contract
|
||||
// as well. You can use Dockerfile.cosmwasm in the root of this repo
|
||||
// to do that.
|
||||
|
||||
import { readdirSync } from "fs";
|
||||
import { DeployerFactory } from "./deployer";
|
||||
import { CONFIG_TYPE, NetworkConfig } from "./deployer/config";
|
||||
|
||||
const ARTIFACT_DIR = "../artifacts/";
|
||||
|
||||
async function deploy() {
|
||||
/*
|
||||
NOTE: Only append to this array: keeping the ordering is crucial, as the
|
||||
contracts must be imported in a deterministic order so their addresses remain
|
||||
deterministic.
|
||||
*/
|
||||
const artifacts = ["wormhole.wasm", "pyth_cosmwasm.wasm"];
|
||||
|
||||
/* Check that the artifact folder contains all the wasm files we expect and nothing else */
|
||||
|
||||
const actual_artifacts = readdirSync("../artifacts/").filter((a) =>
|
||||
a.endsWith(".wasm")
|
||||
);
|
||||
|
||||
const missing_artifacts = artifacts.filter(
|
||||
(a) => !actual_artifacts.includes(a)
|
||||
);
|
||||
if (missing_artifacts.length) {
|
||||
console.log(
|
||||
"Error during terra deployment. The following files are expected to be in the artifacts folder:"
|
||||
);
|
||||
missing_artifacts.forEach((file) => console.log(` - ${file}`));
|
||||
console.log(
|
||||
"Hint: the deploy script needs to run after the contracts have been built."
|
||||
);
|
||||
console.log(
|
||||
"External binary blobs need to be manually added in tools/Dockerfile."
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const unexpected_artifacts = actual_artifacts.filter(
|
||||
(a) => !artifacts.includes(a)
|
||||
);
|
||||
if (unexpected_artifacts.length) {
|
||||
console.log(
|
||||
"Error during terra deployment. The following files are not expected to be in the artifacts folder:"
|
||||
);
|
||||
unexpected_artifacts.forEach((file) => console.log(` - ${file}`));
|
||||
console.log("Hint: you might need to modify tools/deploy.js");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
/* Set up terra deployer */
|
||||
const networkConfig: NetworkConfig = {
|
||||
type: CONFIG_TYPE.TERRA,
|
||||
host: {
|
||||
URL: "http://localhost:1317",
|
||||
chainID: "localterra",
|
||||
name: "localterra",
|
||||
},
|
||||
};
|
||||
const deployer = DeployerFactory.create(
|
||||
networkConfig,
|
||||
"notice oak worry limit wrap speak medal online prefer cluster roof addict wrist behave treat actual wasp year salad speed social layer crew genius"
|
||||
);
|
||||
|
||||
/* Deploy artifacts */
|
||||
const codeIds: Record<string, number> = {};
|
||||
for (const file of artifacts) {
|
||||
const codeId = await deployer.deployArtifact(`../artifacts/${file}`);
|
||||
codeIds[file] = codeId;
|
||||
}
|
||||
console.log(codeIds);
|
||||
|
||||
/* Instantiate contracts.
|
||||
*
|
||||
* We instantiate the core contracts here (i.e. wormhole itself and the bridge contracts).
|
||||
* The wrapped asset contracts don't need to be instantiated here, because those
|
||||
* will be instantiated by the on-chain bridge contracts on demand.
|
||||
* */
|
||||
|
||||
// Instantiate contracts. NOTE: Only append at the end, the ordering must be
|
||||
// deterministic for the addresses to work
|
||||
|
||||
const addresses: Record<string, string> = {};
|
||||
|
||||
let contract = "wormhole.wasm";
|
||||
|
||||
// Governance constants defined by the Wormhole spec.
|
||||
const govChain = 1;
|
||||
const govAddress =
|
||||
"0000000000000000000000000000000000000000000000000000000000000004";
|
||||
|
||||
let inst_msg: Object = {
|
||||
gov_chain: govChain,
|
||||
gov_address: Buffer.from(govAddress, "hex").toString("base64"),
|
||||
guardian_set_expirity: 86400,
|
||||
initial_guardian_set: {
|
||||
addresses: [
|
||||
{
|
||||
bytes: Buffer.from(
|
||||
"beFA429d57cD18b7F8A4d91A2da9AB4AF05d0FBe",
|
||||
"hex"
|
||||
).toString("base64"),
|
||||
},
|
||||
],
|
||||
expiration_time: 0,
|
||||
},
|
||||
chain_id: 18,
|
||||
fee_denom: "uluna",
|
||||
};
|
||||
console.log("Instantiating Wormhole contract");
|
||||
addresses[contract] = await deployer.instantiate(
|
||||
codeIds[contract],
|
||||
inst_msg,
|
||||
"wormhole"
|
||||
);
|
||||
|
||||
contract = "pyth_cosmwasm.wasm";
|
||||
|
||||
const pythEmitterAddress =
|
||||
"71f8dcb863d176e2c420ad6610cf687359612b6fb392e0642b0ca6b1f186aa3b";
|
||||
const pythGovernanceEmitterAddress =
|
||||
"0000000000000000000000000000000000000000000000000000000000001234";
|
||||
const pythChain = 1;
|
||||
|
||||
inst_msg = {
|
||||
wormhole_contract: addresses["wormhole.wasm"],
|
||||
data_sources: [
|
||||
{
|
||||
emitter: Buffer.from(pythEmitterAddress, "hex").toString("base64"),
|
||||
chain_id: pythChain,
|
||||
},
|
||||
],
|
||||
governance_source: {
|
||||
emitter: Buffer.from(pythGovernanceEmitterAddress, "hex").toString(
|
||||
"base64"
|
||||
),
|
||||
chain_id: pythChain,
|
||||
},
|
||||
governance_source_index: 0,
|
||||
governance_sequence_number: 0,
|
||||
chain_id: 3,
|
||||
valid_time_period_secs: 60,
|
||||
fee: {
|
||||
amount: "1",
|
||||
denom: "uluna",
|
||||
},
|
||||
};
|
||||
|
||||
console.log("Instantiating Pyth contract");
|
||||
addresses[contract] = await deployer.instantiate(
|
||||
codeIds[contract],
|
||||
inst_msg,
|
||||
"pyth"
|
||||
);
|
||||
}
|
||||
|
||||
deploy();
|
|
@ -0,0 +1,46 @@
|
|||
import { Network } from "@injectivelabs/networks";
|
||||
import { TerraHost } from "./terra";
|
||||
import { InjectiveHost } from "./injective";
|
||||
import { NETWORKS } from "../network";
|
||||
|
||||
export enum CONFIG_TYPE {
|
||||
TERRA = "terra",
|
||||
INJECTIVE = "injective",
|
||||
}
|
||||
|
||||
export const CONFIG: Config = {
|
||||
[NETWORKS.TERRA_MAINNET]: {
|
||||
type: CONFIG_TYPE.TERRA,
|
||||
host: {
|
||||
URL: "https://phoenix-lcd.terra.dev",
|
||||
chainID: "phoenix-1",
|
||||
name: "mainnet",
|
||||
},
|
||||
},
|
||||
[NETWORKS.TERRA_TESTNET]: {
|
||||
type: CONFIG_TYPE.TERRA,
|
||||
host: {
|
||||
URL: "https://pisco-lcd.terra.dev",
|
||||
chainID: "pisco-1",
|
||||
name: "testnet",
|
||||
},
|
||||
},
|
||||
[NETWORKS.INJECTIVE_TESTNET]: {
|
||||
type: CONFIG_TYPE.INJECTIVE,
|
||||
host: {
|
||||
network: Network.Testnet,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export type Config = Record<NETWORKS, NetworkConfig>;
|
||||
|
||||
export type NetworkConfig =
|
||||
| {
|
||||
type: CONFIG_TYPE.TERRA;
|
||||
host: TerraHost;
|
||||
}
|
||||
| {
|
||||
type: CONFIG_TYPE.INJECTIVE;
|
||||
host: InjectiveHost;
|
||||
};
|
|
@ -0,0 +1,29 @@
|
|||
import { CONFIG, CONFIG_TYPE, NetworkConfig } from "./config";
|
||||
import { TerraDeployer } from "./terra";
|
||||
import { InjectiveDeployer } from "./injective";
|
||||
import { NETWORKS } from "../network";
|
||||
|
||||
export interface Deployer {
|
||||
deployArtifact(artifact: string): Promise<number>;
|
||||
instantiate(
|
||||
codeId: number,
|
||||
inst_msg: string | object,
|
||||
label: string
|
||||
): Promise<string>;
|
||||
migrate(contract: string, codeId: number): Promise<void>;
|
||||
}
|
||||
|
||||
export class DeployerFactory {
|
||||
static create(config: NetworkConfig, mnemonic: string): Deployer {
|
||||
switch (config.type) {
|
||||
case CONFIG_TYPE.TERRA:
|
||||
return TerraDeployer.fromHostAndMnemonic(config.host, mnemonic);
|
||||
|
||||
case CONFIG_TYPE.INJECTIVE:
|
||||
return InjectiveDeployer.fromHostAndMnemonic(config.host, mnemonic);
|
||||
|
||||
default:
|
||||
throw new Error("Invalid config type");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,188 @@
|
|||
import { readFileSync } from "fs";
|
||||
import { Bech32, toHex } from "@cosmjs/encoding";
|
||||
import { zeroPad } from "ethers/lib/utils.js";
|
||||
import assert from "assert";
|
||||
import { getNetworkInfo, Network } from "@injectivelabs/networks";
|
||||
import {
|
||||
DEFAULT_STD_FEE,
|
||||
MsgStoreCode,
|
||||
MsgInstantiateContract,
|
||||
PrivateKey,
|
||||
TxGrpcClient,
|
||||
TxResponse,
|
||||
Msgs,
|
||||
MsgMigrateContract,
|
||||
createTransactionForAddressAndMsg,
|
||||
} from "@injectivelabs/sdk-ts";
|
||||
import { Deployer } from ".";
|
||||
|
||||
export type InjectiveHost = {
|
||||
network: Network;
|
||||
};
|
||||
|
||||
export class InjectiveDeployer implements Deployer {
|
||||
network: Network;
|
||||
wallet: PrivateKey;
|
||||
|
||||
constructor(network: Network, wallet: PrivateKey) {
|
||||
this.network = network;
|
||||
this.wallet = wallet;
|
||||
}
|
||||
|
||||
private injectiveAddress(): string {
|
||||
return this.wallet.toBech32();
|
||||
}
|
||||
|
||||
private async signAndBroadcastMsg(
|
||||
msg: Msgs | MsgMigrateContract,
|
||||
fee = DEFAULT_STD_FEE
|
||||
): Promise<TxResponse> {
|
||||
const networkInfo = getNetworkInfo(this.network);
|
||||
|
||||
const { signBytes, txRaw } = await createTransactionForAddressAndMsg({
|
||||
// @ts-ignore
|
||||
message: msg,
|
||||
address: this.injectiveAddress(),
|
||||
endpoint: networkInfo.rest,
|
||||
chainId: networkInfo.chainId,
|
||||
fee,
|
||||
pubKey: this.wallet.toPublicKey().toBase64(),
|
||||
});
|
||||
|
||||
const sig = await this.wallet.sign(Buffer.from(signBytes));
|
||||
|
||||
/** Append Signatures */
|
||||
txRaw.setSignaturesList([sig]);
|
||||
|
||||
const txService = new TxGrpcClient(networkInfo.grpc);
|
||||
const txResponse = await txService.broadcast(txRaw);
|
||||
|
||||
if (txResponse.code !== 0) {
|
||||
console.error(`Transaction failed: ${txResponse.rawLog}`);
|
||||
} else {
|
||||
console.log(
|
||||
`Broadcasted transaction hash: ${JSON.stringify(txResponse.txHash)}`
|
||||
);
|
||||
}
|
||||
|
||||
return txResponse;
|
||||
}
|
||||
|
||||
async deployArtifact(artifact: string): Promise<number> {
|
||||
const contract_bytes = readFileSync(artifact);
|
||||
console.log(`Storing WASM: ${artifact} (${contract_bytes.length} bytes)`);
|
||||
|
||||
const store_code = MsgStoreCode.fromJSON({
|
||||
sender: this.injectiveAddress(),
|
||||
wasmBytes: contract_bytes,
|
||||
});
|
||||
|
||||
const txResponse = await this.signAndBroadcastMsg(store_code, {
|
||||
amount: [
|
||||
{
|
||||
// gas = 5000000 & gasPrice = 500000000
|
||||
amount: String(500000000 * 5000000),
|
||||
denom: "inj",
|
||||
},
|
||||
],
|
||||
// DEFAULT STD FEE that we use has gas = 400000 and gasPrice = 500000000
|
||||
// But this transaction was taking gas around 3000000. Which is a lot more
|
||||
// Keeping the gasPrice same as in default std fee as seen above in amount.
|
||||
// Changing the gasLimit to 5000000
|
||||
// If similar issue arise saying gas not enough, we can increase it more.
|
||||
gas: "5000000",
|
||||
});
|
||||
|
||||
var codeId: number;
|
||||
try {
|
||||
// {"key":"code_id","value":"\"14\""}
|
||||
const ci = extractFromRawLog(txResponse.rawLog, "code_id");
|
||||
codeId = parseInt(ci);
|
||||
} catch (e) {
|
||||
console.error(
|
||||
"Encountered an error in parsing deploy code result. Printing raw log"
|
||||
);
|
||||
console.error(txResponse.rawLog);
|
||||
throw e;
|
||||
}
|
||||
|
||||
return codeId;
|
||||
}
|
||||
|
||||
async instantiate(
|
||||
codeId: number,
|
||||
inst_msg: object,
|
||||
label: string
|
||||
): Promise<string> {
|
||||
const instantiate_msg = MsgInstantiateContract.fromJSON({
|
||||
sender: this.injectiveAddress(),
|
||||
admin: this.injectiveAddress(),
|
||||
codeId,
|
||||
label,
|
||||
msg: inst_msg,
|
||||
});
|
||||
|
||||
const txResponse = await this.signAndBroadcastMsg(instantiate_msg);
|
||||
|
||||
let address: string = "";
|
||||
try {
|
||||
address = extractFromRawLog(txResponse.rawLog, "contract_address");
|
||||
} catch (e) {
|
||||
console.error(
|
||||
"Encountered an error in parsing instantiation result. Printing raw log"
|
||||
);
|
||||
console.error(txResponse.rawLog);
|
||||
throw e;
|
||||
}
|
||||
|
||||
console.log(
|
||||
`Instantiated Pyth at ${address} (${convert_injective_address_to_hex(
|
||||
address
|
||||
)})`
|
||||
);
|
||||
|
||||
return address;
|
||||
}
|
||||
|
||||
async migrate(contract: string, codeId: number): Promise<void> {
|
||||
const migrate_msg = MsgMigrateContract.fromJSON({
|
||||
sender: this.injectiveAddress(),
|
||||
contract,
|
||||
codeId,
|
||||
msg: {
|
||||
action: "",
|
||||
},
|
||||
});
|
||||
|
||||
const txResponse = await this.signAndBroadcastMsg(migrate_msg);
|
||||
|
||||
let resultCodeId: number;
|
||||
try {
|
||||
resultCodeId = parseInt(extractFromRawLog(txResponse.rawLog, "code_id"));
|
||||
assert.strictEqual(codeId, resultCodeId);
|
||||
} catch (e) {
|
||||
console.error(
|
||||
"Encountered an error in parsing migration result. Printing raw log"
|
||||
);
|
||||
console.error(txResponse.rawLog);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
static fromHostAndMnemonic(host: InjectiveHost, mnemonic: string) {
|
||||
const wallet = PrivateKey.fromMnemonic(mnemonic);
|
||||
return new InjectiveDeployer(host.network, wallet);
|
||||
}
|
||||
}
|
||||
|
||||
// Injective addresses are "human-readable", but for cross-chain registrations, we
|
||||
// want the "canonical" version
|
||||
function convert_injective_address_to_hex(human_addr: string) {
|
||||
return "0x" + toHex(zeroPad(Bech32.decode(human_addr).data, 32));
|
||||
}
|
||||
|
||||
// enter key of what to extract
|
||||
function extractFromRawLog(rawLog: string, key: string): string {
|
||||
const rx = new RegExp(`"${key}","value":"\\\\"([^\\\\"]+)`, "gm");
|
||||
return rx.exec(rawLog)![1];
|
||||
}
|
|
@ -0,0 +1,160 @@
|
|||
import {
|
||||
LCDClient,
|
||||
MnemonicKey,
|
||||
Msg,
|
||||
MsgInstantiateContract,
|
||||
MsgMigrateContract,
|
||||
MsgStoreCode,
|
||||
WaitTxBroadcastResult,
|
||||
Wallet,
|
||||
isTxError,
|
||||
} from "@terra-money/terra.js";
|
||||
import { readFileSync } from "fs";
|
||||
import { Bech32, toHex } from "@cosmjs/encoding";
|
||||
import { zeroPad } from "ethers/lib/utils.js";
|
||||
import assert from "assert";
|
||||
import { Deployer } from ".";
|
||||
|
||||
export type TerraHost = {
|
||||
URL: string;
|
||||
chainID: string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
export class TerraDeployer implements Deployer {
|
||||
wallet: Wallet;
|
||||
feeDenoms: [string];
|
||||
|
||||
constructor(wallet: Wallet) {
|
||||
this.wallet = wallet;
|
||||
this.feeDenoms = ["uluna"];
|
||||
}
|
||||
|
||||
private async signAndBroadcastMsg(msg: Msg): Promise<WaitTxBroadcastResult> {
|
||||
const tx = await this.wallet.createAndSignTx({
|
||||
msgs: [msg],
|
||||
feeDenoms: this.feeDenoms,
|
||||
});
|
||||
const res = await this.wallet.lcd.tx.broadcast(tx);
|
||||
|
||||
if (isTxError(res)) {
|
||||
console.error(`Transaction failed: ${res.raw_log}`);
|
||||
} else {
|
||||
console.log(
|
||||
`Broadcasted transaction hash: ${JSON.stringify(res.txhash)}`
|
||||
);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
async deployArtifact(artifact: string): Promise<number> {
|
||||
const contract_bytes = readFileSync(artifact);
|
||||
console.log(`Storing WASM: ${artifact} (${contract_bytes.length} bytes)`);
|
||||
|
||||
const store_code = new MsgStoreCode(
|
||||
this.wallet.key.accAddress,
|
||||
contract_bytes.toString("base64")
|
||||
);
|
||||
|
||||
const rs = await this.signAndBroadcastMsg(store_code);
|
||||
|
||||
var codeId: number;
|
||||
try {
|
||||
// {"key":"code_id","value":"14"}
|
||||
const ci = extractFromRawLog(rs.raw_log, "code_id");
|
||||
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;
|
||||
}
|
||||
|
||||
return codeId;
|
||||
}
|
||||
|
||||
async instantiate(
|
||||
codeId: number,
|
||||
inst_msg: string | object,
|
||||
label: string
|
||||
): Promise<string> {
|
||||
const instMsg = new MsgInstantiateContract(
|
||||
this.wallet.key.accAddress,
|
||||
this.wallet.key.accAddress,
|
||||
codeId,
|
||||
inst_msg,
|
||||
undefined,
|
||||
label
|
||||
);
|
||||
const rs = await this.signAndBroadcastMsg(instMsg);
|
||||
|
||||
var address: string = "";
|
||||
|
||||
try {
|
||||
// {"key":"_contract_address","value":"terra1xxx3ps3gm3wceg4g300hvggdv7ga0hmsk64srccffmfy4wvcrugqnlvt8w"}
|
||||
address = extractFromRawLog(rs.raw_log, "_contract_address");
|
||||
} catch (e) {
|
||||
console.error(
|
||||
"Encountered an error in parsing instantiation result. Printing raw log"
|
||||
);
|
||||
console.error(rs.raw_log);
|
||||
throw e;
|
||||
}
|
||||
|
||||
console.log(
|
||||
`Instantiated ${label} at ${address} (${convert_terra_address_to_hex(
|
||||
address
|
||||
)})`
|
||||
);
|
||||
return address;
|
||||
}
|
||||
|
||||
async migrate(contract: string, codeId: number): Promise<void> {
|
||||
const migrateMsg = new MsgMigrateContract(
|
||||
this.wallet.key.accAddress,
|
||||
contract,
|
||||
codeId,
|
||||
{
|
||||
action: "",
|
||||
}
|
||||
);
|
||||
|
||||
const rs = await this.signAndBroadcastMsg(migrateMsg);
|
||||
try {
|
||||
// {"key":"code_id","value":"13"}
|
||||
let resultCodeId = parseInt(extractFromRawLog(rs.raw_log, "code_id"));
|
||||
assert.strictEqual(codeId, resultCodeId);
|
||||
} catch (e) {
|
||||
console.error(
|
||||
"Encountered an error in parsing migration result. Printing raw log"
|
||||
);
|
||||
console.error(rs.raw_log);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
static fromHostAndMnemonic(host: TerraHost, mnemonic: string) {
|
||||
const lcd = new LCDClient(host);
|
||||
const wallet = lcd.wallet(
|
||||
new MnemonicKey({
|
||||
mnemonic,
|
||||
})
|
||||
);
|
||||
|
||||
return new TerraDeployer(wallet);
|
||||
}
|
||||
}
|
||||
|
||||
// Terra addresses are "human-readable", but for cross-chain registrations, we
|
||||
// want the "canonical" version
|
||||
function convert_terra_address_to_hex(human_addr: string) {
|
||||
return "0x" + toHex(zeroPad(Bech32.decode(human_addr).data, 32));
|
||||
}
|
||||
|
||||
// enter key of what to extract
|
||||
function extractFromRawLog(rawLog: string, key: string): string {
|
||||
const rx = new RegExp(`"${key}","value":"([^"]+)`, "gm");
|
||||
return rx.exec(rawLog)![1];
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
export enum NETWORKS {
|
||||
TERRA_MAINNET = "terra_mainnet",
|
||||
TERRA_TESTNET = "terra_testnet",
|
||||
INJECTIVE_TESTNET = "injective_testnet",
|
||||
}
|
||||
|
||||
export const NETWORKS_OPTIONS = [
|
||||
NETWORKS.TERRA_MAINNET,
|
||||
NETWORKS.TERRA_TESTNET,
|
||||
NETWORKS.INJECTIVE_TESTNET,
|
||||
];
|
|
@ -0,0 +1,131 @@
|
|||
import { NETWORKS } from "./network";
|
||||
|
||||
export type PythConfig = {
|
||||
wormhole_contract: string;
|
||||
data_sources: DataSource[];
|
||||
governance_source: DataSource;
|
||||
governance_source_index: number;
|
||||
governance_sequence_number: number;
|
||||
chain_id: number;
|
||||
valid_time_period_secs: number;
|
||||
fee: Fee;
|
||||
};
|
||||
|
||||
export type DataSource = {
|
||||
emitter: string;
|
||||
chain_id: number;
|
||||
};
|
||||
|
||||
export type Fee = {
|
||||
amount: string;
|
||||
denom: string;
|
||||
};
|
||||
|
||||
type Config = Record<NETWORKS, PythConfig>;
|
||||
|
||||
export const CONFIG: Config = {
|
||||
[NETWORKS.TERRA_MAINNET]: {
|
||||
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",
|
||||
},
|
||||
},
|
||||
[NETWORKS.TERRA_TESTNET]: {
|
||||
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",
|
||||
},
|
||||
},
|
||||
[NETWORKS.INJECTIVE_TESTNET]: {
|
||||
wormhole_contract: "inj1xx3aupmgv3ce537c0yce8zzd3sz567syuyedpg",
|
||||
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: 19,
|
||||
valid_time_period_secs: 60,
|
||||
fee: {
|
||||
amount: "1",
|
||||
denom: "inj",
|
||||
},
|
||||
},
|
||||
};
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"declaration": true,
|
||||
"target": "es2020",
|
||||
"module": "CommonJS",
|
||||
"moduleResolution": "node",
|
||||
"outDir": "lib",
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"noErrorTruncation": true,
|
||||
"sourceMap": true,
|
||||
"lib": ["es2021"]
|
||||
},
|
||||
"include": ["src/**/*.ts"]
|
||||
}
|
|
@ -63,7 +63,7 @@ spec:
|
|||
value: notice oak worry limit wrap speak medal online prefer cluster roof addict wrist behave treat actual wasp year salad speed social layer crew genius
|
||||
- name: TERRA_PYTH_CONTRACT_ADDRESS
|
||||
value: terra1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrquka9l6
|
||||
# ^^ It can change if order of terra contract creation changes or anything is added/removed in terra/tools/deploy.js
|
||||
# ^^ It can change if order of terra contract creation changes or anything is added/removed in terra/tools/deploy.ts
|
||||
- name: TERRA_CHAIN_ID
|
||||
value: localterra
|
||||
- name: TERRA_NAME
|
||||
|
|
Loading…
Reference in New Issue