clients/js - initial injective commit (#1447)
* clients/js - initial injective commit * clients/js - upgrading the ethers package * clients/js: fix packages
This commit is contained in:
parent
066a2a56aa
commit
66700359f7
|
@ -0,0 +1,191 @@
|
||||||
|
import { getNetworkInfo, Network } from "@injectivelabs/networks";
|
||||||
|
import {
|
||||||
|
MsgExecuteContract,
|
||||||
|
DEFAULT_STD_FEE,
|
||||||
|
privateKeyToPublicKeyBase64,
|
||||||
|
ChainRestAuthApi,
|
||||||
|
} from "@injectivelabs/sdk-ts";
|
||||||
|
import { PrivateKey } from "@injectivelabs/sdk-ts/dist/local";
|
||||||
|
import { createTransaction, MsgArg, TxGrpcClient } from "@injectivelabs/tx-ts";
|
||||||
|
import { fromUint8Array } from "js-base64";
|
||||||
|
import { impossible, Payload } from "./vaa";
|
||||||
|
import { NETWORKS } from "./networks";
|
||||||
|
import { CONTRACTS } from "@certusone/wormhole-sdk";
|
||||||
|
|
||||||
|
export async function execute_injective(
|
||||||
|
payload: Payload,
|
||||||
|
vaa: Buffer,
|
||||||
|
environment: "MAINNET" | "TESTNET" | "DEVNET"
|
||||||
|
) {
|
||||||
|
if (environment === "DEVNET") {
|
||||||
|
throw new Error("Injective is not supported in DEVNET");
|
||||||
|
}
|
||||||
|
const chainName = "injective";
|
||||||
|
let n = NETWORKS[environment][chainName];
|
||||||
|
if (!n.key) {
|
||||||
|
throw Error(`No ${environment} key defined for Injective`);
|
||||||
|
}
|
||||||
|
let contracts = CONTRACTS[environment][chainName];
|
||||||
|
const endPoint =
|
||||||
|
environment === "MAINNET" ? Network.MainnetK8s : Network.TestnetK8s;
|
||||||
|
|
||||||
|
const network = getNetworkInfo(endPoint);
|
||||||
|
const walletPKHash = n.key;
|
||||||
|
const walletPK = PrivateKey.fromPrivateKey(walletPKHash);
|
||||||
|
const walletInjAddr = walletPK.toBech32();
|
||||||
|
const walletPublicKey = privateKeyToPublicKeyBase64(
|
||||||
|
Buffer.from(walletPKHash, "hex")
|
||||||
|
);
|
||||||
|
|
||||||
|
let target_contract: string;
|
||||||
|
let execute_msg: object;
|
||||||
|
|
||||||
|
switch (payload.module) {
|
||||||
|
case "Core":
|
||||||
|
target_contract = contracts.core;
|
||||||
|
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 injective 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 injective");
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
case "Transfer":
|
||||||
|
console.log("Completing transfer");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
impossible(payload);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "TokenBridge":
|
||||||
|
console.log("contracts:", contracts);
|
||||||
|
if (contracts.token_bridge === undefined) {
|
||||||
|
throw new Error("contracts.token_bridge is undefined");
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
case "Transfer":
|
||||||
|
console.log("Completing transfer");
|
||||||
|
break;
|
||||||
|
case "AttestMeta":
|
||||||
|
console.log("Creating wrapped token");
|
||||||
|
break;
|
||||||
|
case "TransferWithPayload":
|
||||||
|
throw Error("Can't complete payload 3 transfer from CLI");
|
||||||
|
default:
|
||||||
|
impossible(payload);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
target_contract = impossible(payload);
|
||||||
|
execute_msg = impossible(payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("execute_msg", execute_msg);
|
||||||
|
const transaction = MsgExecuteContract.fromJSON({
|
||||||
|
sender: walletInjAddr,
|
||||||
|
contractAddress: target_contract,
|
||||||
|
msg: {
|
||||||
|
data: fromUint8Array(vaa),
|
||||||
|
},
|
||||||
|
action: "submit_vaa",
|
||||||
|
});
|
||||||
|
console.log("transaction:", transaction);
|
||||||
|
|
||||||
|
const accountDetails = await new ChainRestAuthApi(
|
||||||
|
network.sentryHttpApi
|
||||||
|
).fetchAccount(walletInjAddr);
|
||||||
|
const { signBytes, txRaw } = createTransaction({
|
||||||
|
message: transaction.toDirectSign(),
|
||||||
|
memo: "",
|
||||||
|
fee: DEFAULT_STD_FEE,
|
||||||
|
pubKey: walletPublicKey,
|
||||||
|
sequence: parseInt(accountDetails.account.base_account.sequence, 10),
|
||||||
|
accountNumber: parseInt(
|
||||||
|
accountDetails.account.base_account.account_number,
|
||||||
|
10
|
||||||
|
),
|
||||||
|
chainId: network.chainId,
|
||||||
|
});
|
||||||
|
console.log("txRaw", txRaw);
|
||||||
|
|
||||||
|
console.log("sign transaction...");
|
||||||
|
/** Sign transaction */
|
||||||
|
const sig = await walletPK.sign(Buffer.from(signBytes));
|
||||||
|
|
||||||
|
/** Append Signatures */
|
||||||
|
txRaw.setSignaturesList([sig]);
|
||||||
|
|
||||||
|
const txService = new TxGrpcClient({
|
||||||
|
txRaw,
|
||||||
|
endpoint: network.sentryGrpcApi,
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("simulate transaction...");
|
||||||
|
/** Simulate transaction */
|
||||||
|
try {
|
||||||
|
const simulationResponse = await txService.simulate();
|
||||||
|
console.log(
|
||||||
|
`Transaction simulation response: ${JSON.stringify(
|
||||||
|
simulationResponse.gasInfo
|
||||||
|
)}`
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
console.log("Failed to simulate:", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("broadcast transaction...");
|
||||||
|
/** Broadcast transaction */
|
||||||
|
const txResponse = await txService.broadcast();
|
||||||
|
console.log("txResponse", txResponse);
|
||||||
|
|
||||||
|
if (txResponse.code !== 0) {
|
||||||
|
console.log(`Transaction failed: ${txResponse.rawLog}`);
|
||||||
|
} else {
|
||||||
|
console.log(
|
||||||
|
`Broadcasted transaction hash: ${JSON.stringify(txResponse.txhash)}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,7 @@ import yargs from "yargs";
|
||||||
|
|
||||||
import { hideBin } from "yargs/helpers";
|
import { hideBin } from "yargs/helpers";
|
||||||
|
|
||||||
import { Bech32, fromBech32, toHex } from "@cosmjs/encoding";
|
import { fromBech32, toHex } from "@cosmjs/encoding";
|
||||||
import {
|
import {
|
||||||
isTerraChain,
|
isTerraChain,
|
||||||
assertEVMChain,
|
assertEVMChain,
|
||||||
|
@ -14,6 +14,7 @@ import {
|
||||||
getEmitterAddressTerra,
|
getEmitterAddressTerra,
|
||||||
getEmitterAddressEth,
|
getEmitterAddressEth,
|
||||||
getEmitterAddressAlgorand,
|
getEmitterAddressAlgorand,
|
||||||
|
isCosmWasmChain,
|
||||||
} from "@certusone/wormhole-sdk";
|
} from "@certusone/wormhole-sdk";
|
||||||
import { execute_solana } from "./solana";
|
import { execute_solana } from "./solana";
|
||||||
import {
|
import {
|
||||||
|
@ -40,6 +41,7 @@ import { ethers } from "ethers";
|
||||||
import { NETWORKS } from "./networks";
|
import { NETWORKS } from "./networks";
|
||||||
import base58 from "bs58";
|
import base58 from "bs58";
|
||||||
import { execute_algorand } from "./algorand";
|
import { execute_algorand } from "./algorand";
|
||||||
|
import { execute_injective } from "./injective";
|
||||||
|
|
||||||
setDefaultWasm("node");
|
setDefaultWasm("node");
|
||||||
|
|
||||||
|
@ -278,9 +280,9 @@ yargs(hideBin(process.argv))
|
||||||
) {
|
) {
|
||||||
throw Error(`Unknown network: ${network}`);
|
throw Error(`Unknown network: ${network}`);
|
||||||
}
|
}
|
||||||
let chain = argv["chain"]
|
let chain = argv["chain"];
|
||||||
let module = argv["module"] as "Core" | "NFTBridge" | "TokenBridge";
|
let module = argv["module"] as "Core" | "NFTBridge" | "TokenBridge";
|
||||||
let addr = ""
|
let addr = "";
|
||||||
switch (module) {
|
switch (module) {
|
||||||
case "Core":
|
case "Core":
|
||||||
addr = CONTRACTS[network][chain]["core"];
|
addr = CONTRACTS[network][chain]["core"];
|
||||||
|
@ -295,7 +297,8 @@ yargs(hideBin(process.argv))
|
||||||
impossible(module);
|
impossible(module);
|
||||||
}
|
}
|
||||||
if (argv["emitter"]) {
|
if (argv["emitter"]) {
|
||||||
if (chain === "solana" || chain === "pythnet") { // TODO: Create an isSolanaChain()
|
if (chain === "solana" || chain === "pythnet") {
|
||||||
|
// TODO: Create an isSolanaChain()
|
||||||
addr = await getEmitterAddressSolana(addr);
|
addr = await getEmitterAddressSolana(addr);
|
||||||
} else if (isTerraChain(chain)) {
|
} else if (isTerraChain(chain)) {
|
||||||
addr = await getEmitterAddressTerra(addr);
|
addr = await getEmitterAddressTerra(addr);
|
||||||
|
@ -303,9 +306,12 @@ yargs(hideBin(process.argv))
|
||||||
addr = getEmitterAddressAlgorand(BigInt(addr));
|
addr = getEmitterAddressAlgorand(BigInt(addr));
|
||||||
} else if (chain === "near") {
|
} else if (chain === "near") {
|
||||||
if (network !== "MAINNET") {
|
if (network !== "MAINNET") {
|
||||||
throw Error(`unable to look up near emitter address for ${network}`);
|
throw Error(
|
||||||
|
`unable to look up near emitter address for ${network}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
addr = "148410499d3fcda4dcfd68a1ebfcdddda16ab28326448d4aae4d2f0465cdfcb7";
|
addr =
|
||||||
|
"148410499d3fcda4dcfd68a1ebfcdddda16ab28326448d4aae4d2f0465cdfcb7";
|
||||||
} else {
|
} else {
|
||||||
addr = getEmitterAddressEth(addr);
|
addr = getEmitterAddressEth(addr);
|
||||||
}
|
}
|
||||||
|
@ -317,8 +323,7 @@ yargs(hideBin(process.argv))
|
||||||
"chain-id <chain>",
|
"chain-id <chain>",
|
||||||
"Print the wormhole chain ID integer associated with the specified chain name",
|
"Print the wormhole chain ID integer associated with the specified chain name",
|
||||||
(yargs) => {
|
(yargs) => {
|
||||||
return yargs
|
return yargs.positional("chain", {
|
||||||
.positional("chain", {
|
|
||||||
describe: "Chain to query",
|
describe: "Chain to query",
|
||||||
type: "string",
|
type: "string",
|
||||||
choices: Object.keys(CHAINS),
|
choices: Object.keys(CHAINS),
|
||||||
|
@ -664,7 +669,7 @@ yargs(hideBin(process.argv))
|
||||||
} else if (chain === "near") {
|
} else if (chain === "near") {
|
||||||
await execute_near(parsed_vaa.payload, vaa_hex, network);
|
await execute_near(parsed_vaa.payload, vaa_hex, network);
|
||||||
} else if (chain === "injective") {
|
} else if (chain === "injective") {
|
||||||
throw Error("INJECTIVE is not supported yet");
|
await execute_injective(parsed_vaa.payload, buf, network);
|
||||||
} else if (chain === "osmosis") {
|
} else if (chain === "osmosis") {
|
||||||
throw Error("OSMOSIS is not supported yet");
|
throw Error("OSMOSIS is not supported yet");
|
||||||
} else if (chain === "sui") {
|
} else if (chain === "sui") {
|
||||||
|
@ -694,7 +699,7 @@ function parseAddress(chain: ChainName, address: string): string {
|
||||||
throw Error("Chain unset");
|
throw Error("Chain unset");
|
||||||
} else if (isEVMChain(chain)) {
|
} else if (isEVMChain(chain)) {
|
||||||
return "0x" + evm_address(address);
|
return "0x" + evm_address(address);
|
||||||
} else if (isTerraChain(chain)) {
|
} else if (isCosmWasmChain(chain)) {
|
||||||
return "0x" + toHex(fromBech32(address).data).padStart(64, "0");
|
return "0x" + toHex(fromBech32(address).data).padStart(64, "0");
|
||||||
} else if (chain === "solana" || chain === "pythnet") {
|
} else if (chain === "solana" || chain === "pythnet") {
|
||||||
return "0x" + toHex(base58.decode(address)).padStart(64, "0");
|
return "0x" + toHex(base58.decode(address)).padStart(64, "0");
|
||||||
|
@ -702,9 +707,7 @@ function parseAddress(chain: ChainName, address: string): string {
|
||||||
// TODO: is there a better native format for algorand?
|
// TODO: is there a better native format for algorand?
|
||||||
return "0x" + evm_address(address);
|
return "0x" + evm_address(address);
|
||||||
} else if (chain === "near") {
|
} else if (chain === "near") {
|
||||||
return "0x" + hex(address).substring(2).padStart(64, "0")
|
return "0x" + hex(address).substring(2).padStart(64, "0");
|
||||||
} else if (chain === "injective") {
|
|
||||||
throw Error("INJECTIVE is not supported yet");
|
|
||||||
} else if (chain === "osmosis") {
|
} else if (chain === "osmosis") {
|
||||||
throw Error("OSMOSIS is not supported yet");
|
throw Error("OSMOSIS is not supported yet");
|
||||||
} else if (chain === "sui") {
|
} else if (chain === "sui") {
|
||||||
|
|
|
@ -82,7 +82,8 @@ const MAINNET = {
|
||||||
rpc: "https://rpc.mainnet.near.org",
|
rpc: "https://rpc.mainnet.near.org",
|
||||||
key: get_env_var("NEAR_KEY"),
|
key: get_env_var("NEAR_KEY"),
|
||||||
networkId: "mainnet",
|
networkId: "mainnet",
|
||||||
deployerAccount: "85957f38de1768d6db9eab29bee9dd2a01462aff9c8d83daefb9bcd2506c32d2",
|
deployerAccount:
|
||||||
|
"85957f38de1768d6db9eab29bee9dd2a01462aff9c8d83daefb9bcd2506c32d2",
|
||||||
},
|
},
|
||||||
injective: {
|
injective: {
|
||||||
rpc: undefined,
|
rpc: undefined,
|
||||||
|
@ -210,12 +211,12 @@ const TESTNET = {
|
||||||
injective: {
|
injective: {
|
||||||
rpc: "https://k8s.testnet.tm.injective.network:443",
|
rpc: "https://k8s.testnet.tm.injective.network:443",
|
||||||
chain_id: "injective-888",
|
chain_id: "injective-888",
|
||||||
key: get_env_var("ETH_KEY_TESTNET"),
|
key: get_env_var("INJECTIVE_KEY_TESTNET"),
|
||||||
},
|
},
|
||||||
osmosis: {
|
osmosis: {
|
||||||
rpc: undefined,
|
rpc: undefined,
|
||||||
chain_id: "osmo-test-4",
|
chain_id: "osmo-test-4",
|
||||||
key: get_env_var("ETH_KEY_TESTNET"),
|
key: get_env_var("OSMOSIS_KEY_TESTNET"),
|
||||||
},
|
},
|
||||||
aptos: {
|
aptos: {
|
||||||
rpc: undefined,
|
rpc: undefined,
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -5,6 +5,9 @@
|
||||||
"@celo-tools/celo-ethers-wrapper": "^0.1.0",
|
"@celo-tools/celo-ethers-wrapper": "^0.1.0",
|
||||||
"@certusone/wormhole-sdk": "^0.7.0",
|
"@certusone/wormhole-sdk": "^0.7.0",
|
||||||
"@cosmjs/encoding": "^0.26.2",
|
"@cosmjs/encoding": "^0.26.2",
|
||||||
|
"@injectivelabs/networks": "^1.0.12",
|
||||||
|
"@injectivelabs/sdk-ts": "^1.0.75",
|
||||||
|
"@injectivelabs/tx-ts": "^1.0.22",
|
||||||
"@solana/web3.js": "^1.22.0",
|
"@solana/web3.js": "^1.22.0",
|
||||||
"@terra-money/terra.js": "^3.1.3",
|
"@terra-money/terra.js": "^3.1.3",
|
||||||
"algosdk": "^1.15.0",
|
"algosdk": "^1.15.0",
|
||||||
|
@ -14,7 +17,7 @@
|
||||||
"bs58": "^4.0.1",
|
"bs58": "^4.0.1",
|
||||||
"buffer-layout": "^1.2.2",
|
"buffer-layout": "^1.2.2",
|
||||||
"dotenv": "^10.0.0",
|
"dotenv": "^10.0.0",
|
||||||
"ethers": "^5.4.1",
|
"ethers": "^5.6.8",
|
||||||
"js-base64": "^3.6.1",
|
"js-base64": "^3.6.1",
|
||||||
"near-api-js": "^0.45.1",
|
"near-api-js": "^0.45.1",
|
||||||
"npm": "^7.20.0",
|
"npm": "^7.20.0",
|
||||||
|
|
Loading…
Reference in New Issue