sdk/js: add injective
This commit is contained in:
parent
34355fd234
commit
239b22e3a8
|
@ -208,12 +208,14 @@ const TESTNET = {
|
|||
deployerAccount: undefined,
|
||||
},
|
||||
injective: {
|
||||
rpc: undefined,
|
||||
key: undefined,
|
||||
rpc: "https://k8s.testnet.tm.injective.network:443",
|
||||
chain_id: "injective-888",
|
||||
key: get_env_var("ETH_KEY_TESTNET"),
|
||||
},
|
||||
osmosis: {
|
||||
rpc: undefined,
|
||||
key: undefined,
|
||||
chain_id: "osmo-test-4",
|
||||
key: get_env_var("ETH_KEY_TESTNET"),
|
||||
},
|
||||
aptos: {
|
||||
rpc: undefined,
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -39,6 +39,8 @@
|
|||
"license": "Apache-2.0",
|
||||
"devDependencies": {
|
||||
"@improbable-eng/grpc-web-node-http-transport": "^0.15.0",
|
||||
"@injectivelabs/networks": "^1.0.12",
|
||||
"@injectivelabs/tx-ts": "^1.0.22",
|
||||
"@openzeppelin/contracts": "^4.2.0",
|
||||
"@typechain/ethers-v5": "^7.0.1",
|
||||
"@types/jest": "^27.0.2",
|
||||
|
@ -58,6 +60,7 @@
|
|||
"dependencies": {
|
||||
"@certusone/wormhole-sdk-proto-web": "^0.0.5",
|
||||
"@certusone/wormhole-sdk-wasm": "^0.0.1",
|
||||
"@injectivelabs/sdk-ts": "^1.0.75",
|
||||
"@solana/spl-token": "^0.1.8",
|
||||
"@solana/web3.js": "^1.24.0",
|
||||
"@terra-money/terra.js": "^3.1.3",
|
||||
|
|
|
@ -366,7 +366,7 @@ export async function signSendAndConfirmAlgorand(
|
|||
const result = await waitForConfirmation(
|
||||
algodClient,
|
||||
txs[txs.length - 1].tx.txID(),
|
||||
1
|
||||
4
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,8 @@ export async function getEmitterAddressTerra(programAddress: string) {
|
|||
).toString("hex");
|
||||
}
|
||||
|
||||
export const getEmitterAddressInjective = getEmitterAddressTerra;
|
||||
|
||||
export function getEmitterAddressAlgorand(appId: bigint): string {
|
||||
const appAddr: string = getApplicationAddress(appId);
|
||||
const decAppAddr: Uint8Array = decodeAddress(appAddr).publicKey;
|
||||
|
|
|
@ -67,6 +67,22 @@ export function parseSequencesFromLogTerra(info: TxInfo): string[] {
|
|||
return sequences;
|
||||
}
|
||||
|
||||
export function parseSequenceFromLogInjective(info: any): string {
|
||||
// Scan for the Sequence attribute in all the outputs of the transaction.
|
||||
let sequence = "";
|
||||
const jsonLog = JSON.parse(info.rawLog);
|
||||
jsonLog.map((row: any) => {
|
||||
row.events.map((event: any) => {
|
||||
event.attributes.map((attribute: any) => {
|
||||
if (attribute.key === "message.sequence") {
|
||||
sequence = attribute.value;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
return sequence.toString();
|
||||
}
|
||||
|
||||
const SOLANA_SEQ_LOG = "Program log: Sequence: ";
|
||||
export function parseSequenceFromLogSolana(info: TransactionResponse) {
|
||||
// TODO: better parsing, safer
|
||||
|
|
|
@ -1,9 +1,36 @@
|
|||
import { keccak256 } from "ethers/lib/utils";
|
||||
import { isNativeDenom } from "../terra";
|
||||
import {
|
||||
CHAIN_ID_INJECTIVE,
|
||||
CHAIN_ID_TERRA,
|
||||
coalesceCosmWasmChainId,
|
||||
CosmWasmChainId,
|
||||
CosmWasmChainName,
|
||||
isTerraChain,
|
||||
} from "../utils";
|
||||
|
||||
export function buildTokenId(address: string) {
|
||||
export const isNativeDenomInjective = (string = "") => string === "inj";
|
||||
|
||||
export function isNativeCosmWasmDenom(
|
||||
chainId: CosmWasmChainId,
|
||||
address: string
|
||||
) {
|
||||
return (
|
||||
(isNativeDenom(address) ? "01" : "00") +
|
||||
(isTerraChain(chainId) && isNativeDenom(address)) ||
|
||||
(chainId === CHAIN_ID_INJECTIVE && isNativeDenomInjective(address))
|
||||
);
|
||||
}
|
||||
|
||||
export function buildTokenId(
|
||||
chain: Exclude<
|
||||
CosmWasmChainId | CosmWasmChainName,
|
||||
typeof CHAIN_ID_TERRA | "terra"
|
||||
>,
|
||||
address: string
|
||||
) {
|
||||
const chainId: CosmWasmChainId = coalesceCosmWasmChainId(chain);
|
||||
return (
|
||||
(isNativeCosmWasmDenom(chainId, address) ? "01" : "00") +
|
||||
keccak256(Buffer.from(address, "utf-8")).substring(4)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
export * from "./address";
|
|
@ -0,0 +1,872 @@
|
|||
require("dotenv").config({ path: ".env" });
|
||||
import { getNetworkInfo, Network } from "@injectivelabs/networks";
|
||||
import {
|
||||
ChainGrpcWasmApi,
|
||||
ChainRestAuthApi,
|
||||
DEFAULT_STD_FEE,
|
||||
privateKeyToPublicKeyBase64,
|
||||
} from "@injectivelabs/sdk-ts";
|
||||
import { createTransaction, MsgArg, TxGrpcClient } from "@injectivelabs/tx-ts";
|
||||
import { PrivateKey } from "@injectivelabs/sdk-ts/dist/local";
|
||||
import { expect, test } from "@jest/globals";
|
||||
import {
|
||||
attestFromAlgorand,
|
||||
attestFromInjective,
|
||||
CHAIN_ID_ALGORAND,
|
||||
CHAIN_ID_INJECTIVE,
|
||||
coalesceChainId,
|
||||
CONTRACTS,
|
||||
createWrappedOnAlgorand,
|
||||
createWrappedOnInjective,
|
||||
getEmitterAddressAlgorand,
|
||||
getEmitterAddressInjective,
|
||||
getForeignAssetInjective,
|
||||
getIsTransferCompletedAlgorand,
|
||||
getIsTransferCompletedInjective,
|
||||
getOriginalAssetInjective,
|
||||
getSignedVAAWithRetry,
|
||||
hexToUint8Array,
|
||||
parseSequenceFromLogAlgorand,
|
||||
parseSequenceFromLogInjective,
|
||||
redeemOnAlgorand,
|
||||
redeemOnInjective,
|
||||
safeBigIntToNumber,
|
||||
textToUint8Array,
|
||||
transferFromAlgorand,
|
||||
transferFromInjective,
|
||||
tryHexToNativeString,
|
||||
tryNativeToHexString,
|
||||
tryNativeToUint8Array,
|
||||
uint8ArrayToHex,
|
||||
} from "..";
|
||||
import { CLUSTER } from "../token_bridge/__tests__/consts";
|
||||
import algosdk, {
|
||||
Account,
|
||||
Algodv2,
|
||||
decodeAddress,
|
||||
makeApplicationCallTxnFromObject,
|
||||
mnemonicToSecretKey,
|
||||
OnApplicationComplete,
|
||||
waitForConfirmation,
|
||||
} from "algosdk";
|
||||
import {
|
||||
getBalances,
|
||||
getForeignAssetFromVaaAlgorand,
|
||||
signSendAndConfirmAlgorand,
|
||||
} from "../algorand/__tests__/testHelpers";
|
||||
import { _parseVAAAlgorand } from "../algorand";
|
||||
import { NodeHttpTransport } from "@improbable-eng/grpc-web-node-http-transport";
|
||||
import { fromUint8Array } from "js-base64";
|
||||
|
||||
function getEndPoint() {
|
||||
return CLUSTER === "mainnet" ? Network.MainnetK8s : Network.TestnetK8s;
|
||||
}
|
||||
|
||||
test.skip("testnet - injective contract is own admin", async () => {
|
||||
const network = getNetworkInfo(getEndPoint());
|
||||
const client = new ChainGrpcWasmApi(network.sentryGrpcApi);
|
||||
const coreQueryResult = await client.fetchContractInfo(
|
||||
CONTRACTS.TESTNET.injective.core
|
||||
);
|
||||
expect(coreQueryResult?.admin).toEqual(CONTRACTS.TESTNET.injective.core);
|
||||
const tbQueryResult = await client.fetchContractInfo(
|
||||
CONTRACTS.TESTNET.injective.token_bridge
|
||||
);
|
||||
expect(tbQueryResult?.admin).toEqual(
|
||||
CONTRACTS.TESTNET.injective.token_bridge
|
||||
);
|
||||
});
|
||||
test.skip("testnet - injective query guardian_set_info", async () => {
|
||||
const network = getNetworkInfo(getEndPoint());
|
||||
const client = new ChainGrpcWasmApi(network.sentryGrpcApi);
|
||||
// https://k8s.testnet.lcd.injective.network/cosmwasm/wasm/v1/contract/inj1xx3aupmgv3ce537c0yce8zzd3sz567syuyedpg/smart/eyJndWFyZGlhbl9zZXRfaW5mbyI6e319
|
||||
const queryResult = await client.fetchSmartContractState(
|
||||
CONTRACTS.TESTNET.injective.core,
|
||||
Buffer.from('{"guardian_set_info":{}}').toString("base64")
|
||||
);
|
||||
let result: any = null;
|
||||
if (typeof queryResult.data === "string") {
|
||||
result = JSON.parse(
|
||||
Buffer.from(queryResult.data, "base64").toString("utf-8")
|
||||
);
|
||||
}
|
||||
expect(result?.guardian_set_index).toEqual(0);
|
||||
expect(result?.addresses.length).toEqual(1);
|
||||
});
|
||||
test.skip("testnet - injective query state", async () => {
|
||||
const network = getNetworkInfo(getEndPoint());
|
||||
const client = new ChainGrpcWasmApi(network.sentryGrpcApi);
|
||||
const queryResult = await client.fetchSmartContractState(
|
||||
CONTRACTS.TESTNET.injective.core,
|
||||
Buffer.from('{"get_state":{}}').toString("base64")
|
||||
);
|
||||
let result: any = null;
|
||||
if (typeof queryResult.data === "string") {
|
||||
result = JSON.parse(
|
||||
Buffer.from(queryResult.data, "base64").toString("utf-8")
|
||||
);
|
||||
}
|
||||
expect(result?.fee?.denom).toEqual("inj");
|
||||
expect(result?.fee?.amount).toEqual("0");
|
||||
});
|
||||
test.skip("testnet - injective query token bridge", async () => {
|
||||
const network = getNetworkInfo(getEndPoint());
|
||||
const client = new ChainGrpcWasmApi(network.sentryGrpcApi);
|
||||
// const wrappedAsset = await getIsWrappedAssetInjective(
|
||||
// CONTRACTS.TESTNET.injective.token_bridge,
|
||||
// "inj10jc4vr9vfq0ykkmfvfgz430w8z6hwdlqhdw9l8"
|
||||
// );
|
||||
// console.log("isWrappedAsset", wrappedAsset);
|
||||
const queryResult = await client.fetchSmartContractState(
|
||||
CONTRACTS.TESTNET.injective.token_bridge,
|
||||
Buffer.from(
|
||||
JSON.stringify({
|
||||
wrapped_registry: {
|
||||
chain: coalesceChainId("injective"),
|
||||
address: tryNativeToHexString(
|
||||
"inj10jc4vr9vfq0ykkmfvfgz430w8z6hwdlqhdw9l8",
|
||||
"injective"
|
||||
),
|
||||
},
|
||||
})
|
||||
).toString("base64")
|
||||
);
|
||||
let result: any = null;
|
||||
if (typeof queryResult.data === "string") {
|
||||
result = JSON.parse(
|
||||
Buffer.from(queryResult.data, "base64").toString("utf-8")
|
||||
);
|
||||
console.log("result", result);
|
||||
}
|
||||
});
|
||||
test.skip("testnet - injective attest native asset", async () => {
|
||||
// Local consts
|
||||
const tba = CONTRACTS.TESTNET.injective.token_bridge;
|
||||
const network = getNetworkInfo(getEndPoint());
|
||||
const client = new ChainGrpcWasmApi(network.sentryGrpcApi);
|
||||
|
||||
// Set up Inj wallet
|
||||
const walletPKHash: string = process.env.ETH_KEY || "";
|
||||
const walletPK = PrivateKey.fromPrivateKey(walletPKHash);
|
||||
const walletInjAddr = walletPK.toBech32();
|
||||
const walletPublicKey = privateKeyToPublicKeyBase64(
|
||||
Buffer.from(walletPKHash, "hex")
|
||||
);
|
||||
const accountDetails = await new ChainRestAuthApi(
|
||||
network.sentryHttpApi
|
||||
).fetchAccount(walletInjAddr);
|
||||
|
||||
// Attest native inj
|
||||
const result = await attestFromInjective(tba, walletInjAddr, "inj");
|
||||
console.log("token", JSON.stringify(result.params.msg));
|
||||
|
||||
// Create the transaction
|
||||
console.log("creating transaction...");
|
||||
const { signBytes, txRaw } = createTransaction({
|
||||
message: result.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,
|
||||
});
|
||||
|
||||
/** Sign transaction */
|
||||
const signature = await walletPK.sign(Buffer.from(signBytes));
|
||||
|
||||
/** Append Signatures */
|
||||
txRaw.setSignaturesList([signature]);
|
||||
const txService = new TxGrpcClient({
|
||||
txRaw,
|
||||
endpoint: network.sentryGrpcApi,
|
||||
});
|
||||
|
||||
console.log("Simulating transaction...");
|
||||
/** Simulate transaction */
|
||||
const simulationResponse = await txService.simulate();
|
||||
console.log(
|
||||
`Transaction simulation response: ${JSON.stringify(
|
||||
simulationResponse.gasInfo
|
||||
)}`
|
||||
);
|
||||
|
||||
/** Broadcast transaction */
|
||||
const txResponse = await txService.broadcast();
|
||||
console.log(
|
||||
`Broadcasted transaction hash: ${JSON.stringify(txResponse.txhash)}`
|
||||
);
|
||||
|
||||
// Need to get the VAA and parse it.
|
||||
const logSeq: string = parseSequenceFromLogInjective(txResponse);
|
||||
console.log("logSeq:", logSeq);
|
||||
const emitterAddress = await getEmitterAddressInjective(
|
||||
CONTRACTS.TESTNET.injective.token_bridge
|
||||
);
|
||||
const rpc: string[] = ["https://wormhole-v2-testnet-api.certus.one"];
|
||||
const { vaaBytes: nativeAssetVaa } = await getSignedVAAWithRetry(
|
||||
rpc,
|
||||
CHAIN_ID_INJECTIVE,
|
||||
emitterAddress,
|
||||
logSeq,
|
||||
{
|
||||
transport: NodeHttpTransport(), //This should only be needed when running in node.
|
||||
},
|
||||
1000, //retryTimeout
|
||||
1000 //Maximum retry attempts
|
||||
);
|
||||
console.log("signed VAA", uint8ArrayToHex(nativeAssetVaa));
|
||||
const parsedVAA = _parseVAAAlgorand(nativeAssetVaa);
|
||||
console.log("parsed attestation vaa", parsedVAA);
|
||||
const assetIdFromVaa = parsedVAA.Contract || "";
|
||||
console.log("assetIdFromVaa:", assetIdFromVaa);
|
||||
|
||||
// const origAsset = await getOriginalAssetInjective(
|
||||
// assetIdFromVaa,
|
||||
// // tryHexToNativeString(assetIdFromVaa, "injective"),
|
||||
// client
|
||||
// );
|
||||
// console.log("origAsset:", origAsset);
|
||||
// const natString = tryHexToNativeString(
|
||||
// uint8ArrayToHex(origAsset.assetAddress),
|
||||
// "injective"
|
||||
// );
|
||||
// console.log("natString:", natString);
|
||||
});
|
||||
test.skip("testnet - injective attest foreign asset", async () => {
|
||||
const tba = CONTRACTS.TESTNET.injective.token_bridge;
|
||||
const wallet = "inj180rl9ezc4389t72pc3vvlkxxs5d9jx60w9eeu3";
|
||||
const foreignAssetAddress = "inj13772jvadyx4j0hrlfh4jzk0v39k8uyfxrfs540";
|
||||
const result = await attestFromInjective(tba, wallet, foreignAssetAddress);
|
||||
console.log("token", JSON.stringify(result.params.msg));
|
||||
console.log("json", result.toJSON());
|
||||
const walletPKHash = process.env.ETH_KEY || "";
|
||||
const walletPK = PrivateKey.fromPrivateKey(walletPKHash);
|
||||
const walletInjAddr = walletPK.toBech32();
|
||||
const walletPublicKey = privateKeyToPublicKeyBase64(
|
||||
Buffer.from(walletPKHash, "hex")
|
||||
);
|
||||
const network = getNetworkInfo(getEndPoint());
|
||||
/** Account Details **/
|
||||
const accountDetails = await new ChainRestAuthApi(
|
||||
network.sentryHttpApi
|
||||
).fetchAccount(walletInjAddr);
|
||||
const { signBytes, txRaw } = createTransaction({
|
||||
message: result.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,
|
||||
});
|
||||
/** Sign transaction */
|
||||
const signature = await walletPK.sign(Buffer.from(signBytes));
|
||||
|
||||
/** Append Signatures */
|
||||
txRaw.setSignaturesList([signature]);
|
||||
const txService = new TxGrpcClient({
|
||||
txRaw,
|
||||
endpoint: network.sentryGrpcApi,
|
||||
});
|
||||
|
||||
/** Simulate transaction */
|
||||
const simulationResponse = await txService.simulate();
|
||||
console.log(
|
||||
`Transaction simulation response: ${JSON.stringify(
|
||||
simulationResponse.gasInfo
|
||||
)}`
|
||||
);
|
||||
|
||||
/** Broadcast transaction */
|
||||
const txResponse = await txService.broadcast();
|
||||
console.log(
|
||||
`Broadcasted transaction hash: ${JSON.stringify(txResponse.txhash)}`
|
||||
);
|
||||
|
||||
// expect(result?.fee?.denom).toEqual("inj");
|
||||
// expect(result?.fee?.amount).toEqual("0");
|
||||
});
|
||||
test.skip("testnet - injective get foreign asset", async () => {
|
||||
const tba = CONTRACTS.TESTNET.injective.token_bridge;
|
||||
const network = getNetworkInfo(getEndPoint());
|
||||
const client = new ChainGrpcWasmApi(network.sentryGrpcApi);
|
||||
// const foreignAssetAddress = "inj10jc4vr9vfq0ykkmfvfgz430w8z6hwdlqhdw9l8";
|
||||
const foreignAssetAddress = "inj13772jvadyx4j0hrlfh4jzk0v39k8uyfxrfs540";
|
||||
const ateArray = tryNativeToUint8Array(foreignAssetAddress, "injective");
|
||||
console.log("wormhole address:", ateArray);
|
||||
const result = await getForeignAssetInjective(
|
||||
tba,
|
||||
client,
|
||||
CHAIN_ID_INJECTIVE,
|
||||
ateArray
|
||||
);
|
||||
console.log("result", result);
|
||||
|
||||
expect(result?.length).toBeGreaterThan(0);
|
||||
});
|
||||
test("testnet - injective submit a vaa", async () => {
|
||||
try {
|
||||
// Set up Algorand side
|
||||
const algodToken = "";
|
||||
const algodServer = "https://testnet-api.algonode.cloud";
|
||||
const algodPort = "";
|
||||
const algodClient = new Algodv2(algodToken, algodServer, algodPort);
|
||||
|
||||
console.log("Doing Algorand part......");
|
||||
console.log("Creating wallet...");
|
||||
const algoWallet: Account = mnemonicToSecretKey(
|
||||
process.env.ALGO_MNEMONIC || ""
|
||||
);
|
||||
|
||||
console.log("wallet", algoWallet);
|
||||
|
||||
const accountInfo = await algodClient
|
||||
.accountInformation(algoWallet.addr)
|
||||
.do();
|
||||
console.log("accountInfo", accountInfo);
|
||||
|
||||
// Attest native ALGO on Algorand
|
||||
// Asset Index of native ALGO is 0
|
||||
const AlgoIndex = BigInt(0);
|
||||
const CoreID = BigInt(86525623); // Testnet
|
||||
const TokenBridgeID = BigInt(86525641); // Testnet
|
||||
const b = await getBalances(algodClient, algoWallet.addr);
|
||||
console.log("balances", b);
|
||||
const txs = await attestFromAlgorand(
|
||||
algodClient,
|
||||
TokenBridgeID,
|
||||
CoreID,
|
||||
algoWallet.addr,
|
||||
AlgoIndex
|
||||
);
|
||||
console.log("txs", txs);
|
||||
|
||||
const result = await signSendAndConfirmAlgorand(
|
||||
algodClient,
|
||||
txs,
|
||||
algoWallet
|
||||
);
|
||||
console.log("result", result);
|
||||
|
||||
const sn = parseSequenceFromLogAlgorand(result);
|
||||
console.log("sn", sn);
|
||||
|
||||
// Now, try to send a NOP
|
||||
const suggParams: algosdk.SuggestedParams = await algodClient
|
||||
.getTransactionParams()
|
||||
.do();
|
||||
const nopTxn = makeApplicationCallTxnFromObject({
|
||||
from: algoWallet.addr,
|
||||
appIndex: safeBigIntToNumber(TokenBridgeID),
|
||||
onComplete: OnApplicationComplete.NoOpOC,
|
||||
appArgs: [textToUint8Array("nop")],
|
||||
suggestedParams: suggParams,
|
||||
});
|
||||
const resp = await algodClient
|
||||
.sendRawTransaction(nopTxn.signTxn(algoWallet.sk))
|
||||
.do();
|
||||
await waitForConfirmation(algodClient, resp.txId, 4);
|
||||
// End of NOP
|
||||
|
||||
// Attestation on Algorand is complete. Get the VAA
|
||||
// Guardian part
|
||||
const rpc: string[] = ["https://wormhole-v2-testnet-api.certus.one"];
|
||||
const emitterAddr = getEmitterAddressAlgorand(BigInt(TokenBridgeID));
|
||||
const { vaaBytes } = await getSignedVAAWithRetry(
|
||||
rpc,
|
||||
CHAIN_ID_ALGORAND,
|
||||
emitterAddr,
|
||||
sn,
|
||||
{ transport: NodeHttpTransport() }
|
||||
);
|
||||
const pvaa = _parseVAAAlgorand(vaaBytes);
|
||||
console.log("parsed vaa", pvaa);
|
||||
|
||||
// Submit the VAA on the Injective side
|
||||
// Start of Injective side
|
||||
console.log("Start doing the Injective part......");
|
||||
const tba = CONTRACTS.TESTNET.injective.token_bridge;
|
||||
const walletPKHash = process.env.ETH_KEY || "";
|
||||
const walletPK = PrivateKey.fromPrivateKey(walletPKHash);
|
||||
const walletInjAddr = walletPK.toBech32();
|
||||
const walletPublicKey = privateKeyToPublicKeyBase64(
|
||||
Buffer.from(walletPKHash, "hex")
|
||||
);
|
||||
const network = getNetworkInfo(getEndPoint());
|
||||
const client = new ChainGrpcWasmApi(network.sentryGrpcApi);
|
||||
console.log("Getting account details...");
|
||||
const accountDetails = await new ChainRestAuthApi(
|
||||
network.sentryHttpApi
|
||||
).fetchAccount(walletInjAddr);
|
||||
console.log("createWrappedOnInjective...", vaaBytes);
|
||||
const msg = await createWrappedOnInjective(tba, walletInjAddr, vaaBytes);
|
||||
console.log("cr", msg);
|
||||
|
||||
console.log("submit_vaa", JSON.stringify(msg.params.msg));
|
||||
/** Prepare the Transaction **/
|
||||
console.log("create transaction...");
|
||||
const txFee = DEFAULT_STD_FEE;
|
||||
txFee.amount[0] = { amount: "250000000000000", denom: "inj" };
|
||||
txFee.gas = "500000";
|
||||
const { signBytes, txRaw } = createTransaction({
|
||||
message: msg.toDirectSign(),
|
||||
memo: "",
|
||||
fee: txFee,
|
||||
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 signature = await walletPK.sign(Buffer.from(signBytes));
|
||||
|
||||
/** Append Signatures */
|
||||
txRaw.setSignaturesList([signature]);
|
||||
|
||||
const txService = new TxGrpcClient({
|
||||
txRaw,
|
||||
endpoint: network.sentryGrpcApi,
|
||||
});
|
||||
|
||||
console.log("simulate transaction...");
|
||||
/** Simulate transaction */
|
||||
const simulationResponse = await txService.simulate();
|
||||
console.log(
|
||||
`Transaction simulation response: ${JSON.stringify(
|
||||
simulationResponse.gasInfo
|
||||
)}`
|
||||
);
|
||||
|
||||
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)}`
|
||||
);
|
||||
}
|
||||
const contract = pvaa.Contract || "0";
|
||||
console.log("contract", contract);
|
||||
const fa = await getForeignAssetInjective(
|
||||
tba,
|
||||
client,
|
||||
"algorand",
|
||||
hexToUint8Array(contract)
|
||||
);
|
||||
console.log("fa", fa);
|
||||
const forAsset = fa || "";
|
||||
// attested Algo contract = inj10jc4vr9vfq0ykkmfvfgz430w8z6hwdlqhdw9l8
|
||||
// Start transfer from Algorand to Injective
|
||||
const AmountToTransfer: number = 12300;
|
||||
const Fee: number = 0;
|
||||
console.log("About to transferFromAlgorand");
|
||||
const transferTxs = await transferFromAlgorand(
|
||||
algodClient,
|
||||
TokenBridgeID,
|
||||
CoreID,
|
||||
algoWallet.addr,
|
||||
AlgoIndex,
|
||||
BigInt(AmountToTransfer),
|
||||
tryNativeToHexString(walletInjAddr, "injective"),
|
||||
CHAIN_ID_INJECTIVE,
|
||||
BigInt(Fee)
|
||||
);
|
||||
console.log("About to signSendAndConfirm");
|
||||
const transferResult = await signSendAndConfirmAlgorand(
|
||||
algodClient,
|
||||
transferTxs,
|
||||
algoWallet
|
||||
);
|
||||
console.log("About to parseSeqFromLog");
|
||||
const txSid = parseSequenceFromLogAlgorand(transferResult);
|
||||
console.log("About to getSignedVAA");
|
||||
const signedVaa = await getSignedVAAWithRetry(
|
||||
rpc,
|
||||
CHAIN_ID_ALGORAND,
|
||||
emitterAddr,
|
||||
txSid,
|
||||
{ transport: NodeHttpTransport() }
|
||||
);
|
||||
const pv = _parseVAAAlgorand(signedVaa.vaaBytes);
|
||||
console.log("vaa", pv);
|
||||
console.log("About to redeemOnInjective");
|
||||
const roi = await redeemOnInjective(tba, walletInjAddr, signedVaa.vaaBytes);
|
||||
console.log("roi", roi);
|
||||
{
|
||||
const accountDetails = await new ChainRestAuthApi(
|
||||
network.sentryHttpApi
|
||||
).fetchAccount(walletInjAddr);
|
||||
const { signBytes, txRaw } = createTransaction({
|
||||
message: roi.toDirectSign(),
|
||||
memo: "",
|
||||
fee: txFee,
|
||||
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 */
|
||||
const simulationResponse = await txService.simulate();
|
||||
console.log(
|
||||
`Transaction simulation response: ${JSON.stringify(
|
||||
simulationResponse.gasInfo
|
||||
)}`
|
||||
);
|
||||
|
||||
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)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
console.log("Checking if transfer is completed");
|
||||
expect(
|
||||
await getIsTransferCompletedInjective(tba, signedVaa.vaaBytes, client)
|
||||
).toBe(true);
|
||||
{
|
||||
console.log("checking vaa:", signedVaa.vaaBytes);
|
||||
console.log("checking vaa:", uint8ArrayToHex(signedVaa.vaaBytes));
|
||||
const network = getNetworkInfo(getEndPoint());
|
||||
const client = new ChainGrpcWasmApi(network.sentryGrpcApi);
|
||||
const queryResult = await client.fetchSmartContractState(
|
||||
CONTRACTS.TESTNET.injective.token_bridge,
|
||||
Buffer.from(
|
||||
JSON.stringify({
|
||||
transfer_info: {
|
||||
vaa: fromUint8Array(signedVaa.vaaBytes),
|
||||
},
|
||||
})
|
||||
).toString("base64")
|
||||
);
|
||||
let result: any = null;
|
||||
let addr: string = "";
|
||||
if (typeof queryResult.data === "string") {
|
||||
result = JSON.parse(
|
||||
Buffer.from(queryResult.data, "base64").toString("utf-8")
|
||||
);
|
||||
console.log("result", result);
|
||||
addr = tryHexToNativeString(
|
||||
uint8ArrayToHex(result.recipient),
|
||||
"injective"
|
||||
);
|
||||
console.log("Injective address?", addr);
|
||||
}
|
||||
// interface wAlgoBalance {
|
||||
// balance: string;
|
||||
// }
|
||||
|
||||
console.log(
|
||||
"Getting balance for foreign asset",
|
||||
forAsset,
|
||||
"on address",
|
||||
walletInjAddr
|
||||
);
|
||||
const balRes = await client.fetchSmartContractState(
|
||||
forAsset,
|
||||
Buffer.from(
|
||||
JSON.stringify({
|
||||
balance: {
|
||||
address: walletInjAddr,
|
||||
},
|
||||
})
|
||||
).toString("base64")
|
||||
);
|
||||
result = null;
|
||||
console.log("balRes", balRes);
|
||||
if (typeof balRes.data === "string") {
|
||||
result = JSON.parse(
|
||||
Buffer.from(balRes.data, "base64").toString("utf-8")
|
||||
);
|
||||
console.log("balRes", result);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
});
|
||||
|
||||
test.skip("Attest and transfer token from Injective to Algorand", async () => {
|
||||
const Asset: string = "inj";
|
||||
const walletPKHash: string = process.env.INJ_PK_HASH || "";
|
||||
const walletPK = PrivateKey.fromPrivateKey(walletPKHash);
|
||||
const walletInjAddr = walletPK.toBech32();
|
||||
const walletPublicKey = privateKeyToPublicKeyBase64(
|
||||
Buffer.from(walletPKHash, "hex")
|
||||
);
|
||||
const network = getNetworkInfo(getEndPoint());
|
||||
console.log("create transaction...");
|
||||
const txFee = DEFAULT_STD_FEE;
|
||||
txFee.amount[0] = { amount: "250000000000000", denom: "inj" };
|
||||
txFee.gas = "500000";
|
||||
// Attest
|
||||
const attestMsg = await attestFromInjective(
|
||||
CONTRACTS.TESTNET.injective.token_bridge,
|
||||
walletInjAddr,
|
||||
Asset
|
||||
);
|
||||
|
||||
const accountDetails = await new ChainRestAuthApi(
|
||||
network.sentryHttpApi
|
||||
).fetchAccount(walletInjAddr);
|
||||
const { signBytes, txRaw } = createTransaction({
|
||||
message: attestMsg.toDirectSign(),
|
||||
memo: "",
|
||||
fee: txFee,
|
||||
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 signedMsg = await walletPK.sign(Buffer.from(signBytes));
|
||||
|
||||
/** Append Signatures */
|
||||
txRaw.setSignaturesList([signedMsg]);
|
||||
|
||||
const txService = new TxGrpcClient({
|
||||
txRaw,
|
||||
endpoint: network.sentryGrpcApi,
|
||||
});
|
||||
|
||||
console.log("simulate transaction...");
|
||||
/** Simulate transaction */
|
||||
const simulationResponse = await txService.simulate();
|
||||
console.log(
|
||||
`Transaction simulation response: ${JSON.stringify(
|
||||
simulationResponse.gasInfo
|
||||
)}`
|
||||
);
|
||||
|
||||
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)}`
|
||||
);
|
||||
}
|
||||
console.log("txResponse", JSON.stringify(txResponse.rawLog));
|
||||
console.log("txResponse", txResponse.rawLog);
|
||||
const sequence = parseSequenceFromLogInjective(txResponse);
|
||||
if (!sequence) {
|
||||
throw new Error("Sequence not found");
|
||||
}
|
||||
console.log("found seqNum:", sequence);
|
||||
const emitterAddress = await getEmitterAddressInjective(
|
||||
CONTRACTS.TESTNET.injective.token_bridge
|
||||
);
|
||||
const rpc: string[] = ["https://wormhole-v2-testnet-api.certus.one"];
|
||||
const { vaaBytes: attestSignedVaa } = await getSignedVAAWithRetry(
|
||||
rpc,
|
||||
CHAIN_ID_INJECTIVE,
|
||||
emitterAddress,
|
||||
sequence,
|
||||
{
|
||||
transport: NodeHttpTransport(), //This should only be needed when running in node.
|
||||
},
|
||||
1000, //retryTimeout
|
||||
1000 //Maximum retry attempts
|
||||
);
|
||||
console.log("signed VAA", uint8ArrayToHex(attestSignedVaa));
|
||||
console.log("parsed attestation vaa", _parseVAAAlgorand(attestSignedVaa));
|
||||
|
||||
const algodToken = "";
|
||||
const algodServer = "https://testnet-api.algonode.cloud";
|
||||
const algodPort = "";
|
||||
const algodClient = new Algodv2(algodToken, algodServer, algodPort);
|
||||
|
||||
console.log("Doing Algorand part......");
|
||||
console.log("Creating wallet...");
|
||||
if (!process.env.ALGO_MNEMONIC) {
|
||||
throw new Error("Failed to read in ALGO_MNEMONIC");
|
||||
}
|
||||
const algoWallet: Account = mnemonicToSecretKey(process.env.ALGO_MNEMONIC);
|
||||
const CoreID = BigInt(86525623); // Testnet
|
||||
const TokenBridgeID = BigInt(86525641); // Testnet
|
||||
console.log("createWrappedOnAlgorand...");
|
||||
const createWrappedTxs = await createWrappedOnAlgorand(
|
||||
algodClient,
|
||||
TokenBridgeID,
|
||||
CoreID,
|
||||
algoWallet.addr,
|
||||
attestSignedVaa
|
||||
);
|
||||
console.log("signing and sending to algorand...");
|
||||
const sscResult = await signSendAndConfirmAlgorand(
|
||||
algodClient,
|
||||
createWrappedTxs,
|
||||
algoWallet
|
||||
);
|
||||
console.log("sscResult", sscResult);
|
||||
|
||||
console.log("getting foreign asset:");
|
||||
let assetIdCreated = await getForeignAssetFromVaaAlgorand(
|
||||
algodClient,
|
||||
TokenBridgeID,
|
||||
attestSignedVaa
|
||||
);
|
||||
if (!assetIdCreated) {
|
||||
throw new Error("Failed to create asset");
|
||||
}
|
||||
console.log("assetId:", assetIdCreated);
|
||||
// Transfer
|
||||
const transferMsgs = await transferFromInjective(
|
||||
walletInjAddr,
|
||||
CONTRACTS.TESTNET.injective.token_bridge,
|
||||
"inj",
|
||||
"1000000",
|
||||
CHAIN_ID_ALGORAND,
|
||||
decodeAddress(algoWallet.addr).publicKey
|
||||
);
|
||||
console.log("number of msgs = ", transferMsgs.length);
|
||||
let xferMsgsSigned: MsgArg[] = transferMsgs.map((element) =>
|
||||
element.toDirectSign()
|
||||
);
|
||||
{
|
||||
console.log("xferMsgsSigned", xferMsgsSigned);
|
||||
const { signBytes, txRaw } = createTransaction({
|
||||
message: xferMsgsSigned,
|
||||
memo: "",
|
||||
fee: txFee,
|
||||
pubKey: walletPublicKey,
|
||||
sequence:
|
||||
parseInt(accountDetails.account.base_account.sequence, 10) +
|
||||
xferMsgsSigned.length -
|
||||
1,
|
||||
accountNumber: parseInt(
|
||||
accountDetails.account.base_account.account_number,
|
||||
10
|
||||
),
|
||||
chainId: network.chainId,
|
||||
});
|
||||
console.log("txRaw", txRaw);
|
||||
|
||||
console.log("sign transaction...");
|
||||
/** Sign transaction */
|
||||
const signedMsg = await walletPK.sign(Buffer.from(signBytes));
|
||||
|
||||
/** Append Signatures */
|
||||
txRaw.setSignaturesList([signedMsg]);
|
||||
|
||||
const txService = new TxGrpcClient({
|
||||
txRaw,
|
||||
endpoint: network.sentryGrpcApi,
|
||||
});
|
||||
|
||||
console.log("simulate transaction...");
|
||||
/** Simulate transaction */
|
||||
const simulationResponse = await txService.simulate();
|
||||
console.log(
|
||||
`Transaction simulation response: ${JSON.stringify(
|
||||
simulationResponse.gasInfo
|
||||
)}`
|
||||
);
|
||||
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)}`
|
||||
);
|
||||
}
|
||||
console.log("txResponse", JSON.stringify(txResponse));
|
||||
|
||||
const sequence = parseSequenceFromLogInjective(txResponse);
|
||||
if (!sequence) {
|
||||
throw new Error("Sequence not found");
|
||||
}
|
||||
console.log("found seqNum:", sequence);
|
||||
const { vaaBytes } = await getSignedVAAWithRetry(
|
||||
rpc,
|
||||
CHAIN_ID_INJECTIVE,
|
||||
emitterAddress,
|
||||
sequence,
|
||||
{
|
||||
transport: NodeHttpTransport(), //This should only be needed when running in node.
|
||||
},
|
||||
1000, //retryTimeout
|
||||
1000 //Maximum retry attempts
|
||||
);
|
||||
console.log("parsed VAA", _parseVAAAlgorand(vaaBytes));
|
||||
console.log("About to redeemOnAlgorand...");
|
||||
const tids = await redeemOnAlgorand(
|
||||
algodClient,
|
||||
TokenBridgeID,
|
||||
CoreID,
|
||||
vaaBytes,
|
||||
algoWallet.addr
|
||||
);
|
||||
console.log("After redeem...", tids);
|
||||
const resToLog = await signSendAndConfirmAlgorand(
|
||||
algodClient,
|
||||
tids,
|
||||
algoWallet
|
||||
);
|
||||
console.log("resToLog", resToLog["confirmed-round"]);
|
||||
console.log("Checking if isRedeemed...");
|
||||
const success = await getIsTransferCompletedAlgorand(
|
||||
algodClient,
|
||||
TokenBridgeID,
|
||||
vaaBytes
|
||||
);
|
||||
expect(success).toBe(true);
|
||||
}
|
||||
const balances = await getBalances(algodClient, algoWallet.addr);
|
||||
console.log("Ending balances", balances);
|
||||
});
|
|
@ -0,0 +1,108 @@
|
|||
import { getNetworkInfo, Network } from "@injectivelabs/networks";
|
||||
import {
|
||||
ChainRestAuthApi,
|
||||
DEFAULT_STD_FEE,
|
||||
MsgExecuteContract,
|
||||
privateKeyToPublicKeyBase64,
|
||||
} from "@injectivelabs/sdk-ts";
|
||||
import {
|
||||
createTransaction,
|
||||
TxClient,
|
||||
TxGrpcClient,
|
||||
} from "@injectivelabs/tx-ts";
|
||||
import { PrivateKey } from "@injectivelabs/sdk-ts/dist/local";
|
||||
import { test } from "@jest/globals";
|
||||
import { CONTRACTS } from "..";
|
||||
|
||||
test.skip("testnet - injective attest native token", async () => {
|
||||
const network = getNetworkInfo(Network.TestnetK8s);
|
||||
console.log("Using network:", network);
|
||||
const privateKeyHash = process.env.ETH_KEY || "";
|
||||
const privateKey = PrivateKey.fromPrivateKey(privateKeyHash);
|
||||
const injectiveAddress = privateKey.toBech32();
|
||||
console.log("Using wallet:", injectiveAddress);
|
||||
const publicKey = privateKeyToPublicKeyBase64(
|
||||
Buffer.from(privateKeyHash, "hex")
|
||||
);
|
||||
const isNativeAsset = true;
|
||||
const asset = "inj";
|
||||
const nonce = 69;
|
||||
|
||||
console.log("Account details");
|
||||
|
||||
/** Account Details **/
|
||||
const accountDetails = await new ChainRestAuthApi(
|
||||
network.sentryHttpApi
|
||||
).fetchAccount(injectiveAddress);
|
||||
console.log(accountDetails);
|
||||
|
||||
/** Prepare the Message */
|
||||
console.log("Prepare the message");
|
||||
const msg = MsgExecuteContract.fromJSON({
|
||||
contractAddress: CONTRACTS.TESTNET.injective.token_bridge,
|
||||
sender: injectiveAddress,
|
||||
msg: {
|
||||
asset_info: isNativeAsset
|
||||
? {
|
||||
native_token: { denom: asset },
|
||||
}
|
||||
: {
|
||||
token: {
|
||||
contract_addr: asset,
|
||||
},
|
||||
},
|
||||
nonce: nonce,
|
||||
},
|
||||
action: "create_asset_meta",
|
||||
});
|
||||
|
||||
/** Prepare the Transaction **/
|
||||
console.log("Prepare the transaction");
|
||||
const { signBytes, txRaw } = createTransaction({
|
||||
message: msg.toDirectSign(),
|
||||
memo: "",
|
||||
fee: DEFAULT_STD_FEE,
|
||||
pubKey: publicKey,
|
||||
sequence: parseInt(accountDetails.account.base_account.sequence, 10),
|
||||
accountNumber: parseInt(
|
||||
accountDetails.account.base_account.account_number,
|
||||
10
|
||||
),
|
||||
chainId: network.chainId,
|
||||
});
|
||||
|
||||
/** Sign transaction */
|
||||
console.log("Sign transaction");
|
||||
const signature = await privateKey.sign(Buffer.from(signBytes));
|
||||
|
||||
/** Append Signatures */
|
||||
console.log("Append signatures");
|
||||
txRaw.setSignaturesList([signature]);
|
||||
|
||||
/** Calculate hash of the transaction */
|
||||
console.log("Calculate hash");
|
||||
console.log(`Transaction Hash: ${await TxClient.hash(txRaw)}`);
|
||||
|
||||
const txService = new TxGrpcClient({
|
||||
txRaw,
|
||||
endpoint: network.sentryGrpcApi,
|
||||
});
|
||||
|
||||
/** Simulate transaction */
|
||||
console.log("Simulate transaction");
|
||||
const simulationResponse = await txService.simulate();
|
||||
console.log(
|
||||
`Transaction simulation response: ${JSON.stringify(
|
||||
simulationResponse.gasInfo
|
||||
)}`
|
||||
);
|
||||
|
||||
/** Broadcast transaction */
|
||||
console.log("Broadcast transaction");
|
||||
const txResponse = await txService.broadcast();
|
||||
console.log(
|
||||
`Broadcasted transaction hash: ${JSON.stringify(txResponse.txhash)}`
|
||||
);
|
||||
|
||||
console.log(txResponse);
|
||||
});
|
|
@ -1,5 +1,6 @@
|
|||
import { Connection, Keypair, PublicKey, Transaction } from "@solana/web3.js";
|
||||
import { MsgExecuteContract } from "@terra-money/terra.js";
|
||||
import { MsgExecuteContract as MsgExecuteContractInjective } from "@injectivelabs/sdk-ts";
|
||||
import {
|
||||
Algodv2,
|
||||
bigIntToBytes,
|
||||
|
@ -24,6 +25,7 @@ import { createNonce } from "../utils/createNonce";
|
|||
import { parseSequenceFromLogNear } from "../bridge/parseSequenceFromLog";
|
||||
|
||||
import { getIsWrappedAssetNear } from ".";
|
||||
import { isNativeDenomInjective } from "../cosmwasm";
|
||||
|
||||
export async function attestFromEth(
|
||||
tokenBridgeAddress: string,
|
||||
|
@ -60,6 +62,41 @@ export async function attestFromTerra(
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates attestation message
|
||||
* @param tokenBridgeAddress Address of Inj token bridge contract
|
||||
* @param walletAddress Address of wallet in inj format
|
||||
* @param asset Name or address of the asset to be attested
|
||||
* For native assets the asset string is the denomination.
|
||||
* For foreign assets the asset string is the inj address of the foreign asset
|
||||
* @returns Message to be broadcast
|
||||
*/
|
||||
export async function attestFromInjective(
|
||||
tokenBridgeAddress: string,
|
||||
walletAddress: string,
|
||||
asset: string
|
||||
): Promise<MsgExecuteContractInjective> {
|
||||
const nonce = Math.round(Math.random() * 100000);
|
||||
const isNativeAsset = isNativeDenomInjective(asset);
|
||||
return MsgExecuteContractInjective.fromJSON({
|
||||
contractAddress: tokenBridgeAddress,
|
||||
sender: walletAddress,
|
||||
msg: {
|
||||
asset_info: isNativeAsset
|
||||
? {
|
||||
native_token: { denom: asset },
|
||||
}
|
||||
: {
|
||||
token: {
|
||||
contract_addr: asset,
|
||||
},
|
||||
},
|
||||
nonce: nonce,
|
||||
},
|
||||
action: "create_asset_meta",
|
||||
});
|
||||
}
|
||||
|
||||
export async function attestFromSolana(
|
||||
connection: Connection,
|
||||
bridgeAddress: string,
|
||||
|
|
|
@ -7,7 +7,11 @@ import { TransactionSignerPair, _submitVAAAlgorand } from "../algorand";
|
|||
import { Bridge__factory } from "../ethers-contracts";
|
||||
import { ixFromRust } from "../solana";
|
||||
import { importTokenWasm } from "../solana/wasm";
|
||||
import { Account as nearAccount, providers as nearProviders } from "near-api-js";
|
||||
import { submitVAAOnInjective } from "./redeem";
|
||||
import {
|
||||
Account as nearAccount,
|
||||
providers as nearProviders,
|
||||
} from "near-api-js";
|
||||
import BN from "bn.js";
|
||||
|
||||
export async function createWrappedOnEth(
|
||||
|
@ -34,6 +38,8 @@ export async function createWrappedOnTerra(
|
|||
});
|
||||
}
|
||||
|
||||
export const createWrappedOnInjective = submitVAAOnInjective;
|
||||
|
||||
export async function createWrappedOnSolana(
|
||||
connection: Connection,
|
||||
bridgeAddress: string,
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import { Connection, PublicKey } from "@solana/web3.js";
|
||||
import { LCDClient } from "@terra-money/terra.js";
|
||||
import { ChainGrpcWasmApi } from "@injectivelabs/sdk-ts";
|
||||
import { getNetworkInfo, Network } from "@injectivelabs/networks";
|
||||
import { Algodv2 } from "algosdk";
|
||||
import { ethers } from "ethers";
|
||||
import { fromUint8Array } from "js-base64";
|
||||
|
@ -66,6 +68,44 @@ export async function getForeignAssetTerra(
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the address of the foreign asset
|
||||
* @param tokenBridgeAddress Address of token bridge contact
|
||||
* @param client Holds the wallet and signing information
|
||||
* @param originChain The chainId of the origin of the asset
|
||||
* @param originAsset The address of the origin asset
|
||||
* @returns The foreign asset address or null
|
||||
*/
|
||||
export async function getForeignAssetInjective(
|
||||
tokenBridgeAddress: string,
|
||||
client: ChainGrpcWasmApi,
|
||||
originChain: ChainId | ChainName,
|
||||
originAsset: Uint8Array
|
||||
): Promise<string | null> {
|
||||
try {
|
||||
const queryResult = await client.fetchSmartContractState(
|
||||
tokenBridgeAddress,
|
||||
Buffer.from(
|
||||
JSON.stringify({
|
||||
wrapped_registry: {
|
||||
chain: coalesceChainId(originChain),
|
||||
address: fromUint8Array(originAsset),
|
||||
},
|
||||
})
|
||||
).toString("base64")
|
||||
);
|
||||
let result: any = null;
|
||||
if (typeof queryResult.data === "string") {
|
||||
result = JSON.parse(
|
||||
Buffer.from(queryResult.data, "base64").toString("utf-8")
|
||||
);
|
||||
}
|
||||
return result.address;
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a foreign asset address on Solana for a provided native chain and asset address
|
||||
* @param connection
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { ChainGrpcWasmApi } from "@injectivelabs/sdk-ts";
|
||||
import { Connection, PublicKey } from "@solana/web3.js";
|
||||
import { LCDClient } from "@terra-money/terra.js";
|
||||
import { Algodv2, bigIntToBytes } from "algosdk";
|
||||
|
@ -80,7 +81,7 @@ export async function getIsTransferCompletedTerra(
|
|||
export async function getIsTransferCompletedTerra2(
|
||||
tokenBridgeAddress: string,
|
||||
signedVAA: Uint8Array,
|
||||
client: LCDClient,
|
||||
client: LCDClient
|
||||
): Promise<boolean> {
|
||||
const result: { is_redeemed: boolean } = await client.wasm.contractQuery(
|
||||
tokenBridgeAddress,
|
||||
|
@ -93,6 +94,37 @@ export async function getIsTransferCompletedTerra2(
|
|||
return result.is_redeemed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the VAA has been redeemed or not
|
||||
* @param tokenBridgeAddress The Injective token bridge contract address
|
||||
* @param signedVAA The signed VAA byte array
|
||||
* @param client Holds the wallet and signing information
|
||||
* @returns true if the VAA has been redeemed.
|
||||
*/
|
||||
export async function getIsTransferCompletedInjective(
|
||||
tokenBridgeAddress: string,
|
||||
signedVAA: Uint8Array,
|
||||
client: ChainGrpcWasmApi
|
||||
): Promise<boolean> {
|
||||
const queryResult = await client.fetchSmartContractState(
|
||||
tokenBridgeAddress,
|
||||
Buffer.from(
|
||||
JSON.stringify({
|
||||
is_vaa_redeemed: {
|
||||
vaa: fromUint8Array(signedVAA),
|
||||
},
|
||||
})
|
||||
).toString("base64")
|
||||
);
|
||||
if (typeof queryResult.data === "string") {
|
||||
const result = JSON.parse(
|
||||
Buffer.from(queryResult.data, "base64").toString("utf-8")
|
||||
);
|
||||
return result.is_redeemed;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export async function getIsTransferCompletedSolana(
|
||||
tokenBridgeAddress: string,
|
||||
signedVAA: Uint8Array,
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
import { ChainGrpcWasmApi } from "@injectivelabs/sdk-ts";
|
||||
import { Connection, PublicKey } from "@solana/web3.js";
|
||||
import { LCDClient } from "@terra-money/terra.js";
|
||||
import { Algodv2, getApplicationAddress } from "algosdk";
|
||||
import { ethers } from "ethers";
|
||||
import { Bridge__factory } from "../ethers-contracts";
|
||||
import { importTokenWasm } from "../solana/wasm";
|
||||
import { CHAIN_ID_INJECTIVE, tryNativeToHexString } from "../utils";
|
||||
import { safeBigIntToNumber } from "../utils/bigint";
|
||||
import { getForeignAssetInjective } from "./getForeignAsset";
|
||||
|
||||
/**
|
||||
* Returns whether or not an asset address on Ethereum is a wormhole wrapped asset
|
||||
|
@ -32,6 +35,31 @@ export async function getIsWrappedAssetTerra(
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the asset is a wrapped asset
|
||||
* @param tokenBridgeAddress The address of the Injective token bridge contract
|
||||
* @param client Connection/wallet information
|
||||
* @param assetAddress Address of the asset in Injective format
|
||||
* @returns true if asset is a wormhole wrapped asset
|
||||
*/
|
||||
export async function getIsWrappedAssetInjective(
|
||||
tokenBridgeAddress: string,
|
||||
client: ChainGrpcWasmApi,
|
||||
assetAddress: string
|
||||
): Promise<boolean> {
|
||||
const hexified = tryNativeToHexString(assetAddress, "injective");
|
||||
const result = await getForeignAssetInjective(
|
||||
tokenBridgeAddress,
|
||||
client,
|
||||
CHAIN_ID_INJECTIVE,
|
||||
new Uint8Array(Buffer.from(hexified))
|
||||
);
|
||||
if (result === null) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not an asset on Solana is a wormhole wrapped asset
|
||||
* @param connection
|
||||
|
@ -90,5 +118,5 @@ export function getIsWrappedAssetNear(
|
|||
tokenBridge: string,
|
||||
asset: string
|
||||
): boolean {
|
||||
return asset.endsWith("." + tokenBridge);
|
||||
return asset.endsWith("." + tokenBridge);
|
||||
}
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
const sha256 = require("js-sha256");
|
||||
|
||||
import { getNetworkInfo, Network } from "@injectivelabs/networks";
|
||||
import { ChainGrpcWasmApi } from "@injectivelabs/sdk-ts";
|
||||
import { Connection, PublicKey } from "@solana/web3.js";
|
||||
import { LCDClient } from "@terra-money/terra.js";
|
||||
import { Algodv2 } from "algosdk";
|
||||
import { ethers } from "ethers";
|
||||
import { arrayify, zeroPad } from "ethers/lib/utils";
|
||||
import { decodeLocalState } from "../algorand";
|
||||
import { buildTokenId } from "../cosmwasm/address";
|
||||
import { buildTokenId, isNativeCosmWasmDenom } from "../cosmwasm/address";
|
||||
import { TokenImplementation__factory } from "../ethers-contracts";
|
||||
import { importTokenWasm } from "../solana/wasm";
|
||||
import { buildNativeId, isNativeDenom } from "../terra";
|
||||
|
@ -16,10 +18,15 @@ import {
|
|||
ChainName,
|
||||
CHAIN_ID_ALGORAND,
|
||||
CHAIN_ID_NEAR,
|
||||
CHAIN_ID_INJECTIVE,
|
||||
CHAIN_ID_SOLANA,
|
||||
CHAIN_ID_TERRA,
|
||||
coalesceChainId,
|
||||
CosmWasmChainId,
|
||||
CosmWasmChainName,
|
||||
hexToUint8Array,
|
||||
coalesceCosmWasmChainId,
|
||||
tryHexToNativeAssetString,
|
||||
} from "../utils";
|
||||
import { safeBigIntToNumber } from "../utils/bigint";
|
||||
import {
|
||||
|
@ -81,20 +88,74 @@ export async function getOriginalAssetTerra(
|
|||
return getOriginalAssetCosmWasm(client, wrappedAddress, CHAIN_ID_TERRA);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns information about the asset
|
||||
* @param wrappedAddress Address of the asset in wormhole wrapped format (hex string)
|
||||
* @param client WASM api client
|
||||
* @returns Information about the asset
|
||||
*/
|
||||
export async function getOriginalAssetInjective(
|
||||
wrappedAddress: string,
|
||||
client: ChainGrpcWasmApi
|
||||
): Promise<WormholeWrappedInfo> {
|
||||
const chainId = CHAIN_ID_INJECTIVE;
|
||||
if (isNativeCosmWasmDenom(CHAIN_ID_INJECTIVE, wrappedAddress)) {
|
||||
return {
|
||||
isWrapped: false,
|
||||
chainId: chainId,
|
||||
assetAddress: hexToUint8Array(buildTokenId(chainId, wrappedAddress)),
|
||||
};
|
||||
}
|
||||
try {
|
||||
const injWrappedAddress = tryHexToNativeAssetString(
|
||||
wrappedAddress,
|
||||
CHAIN_ID_INJECTIVE
|
||||
);
|
||||
const queryResult = await client.fetchSmartContractState(
|
||||
injWrappedAddress,
|
||||
Buffer.from(
|
||||
JSON.stringify({
|
||||
wrapped_asset_info: {},
|
||||
})
|
||||
).toString("base64")
|
||||
);
|
||||
let result: any = null;
|
||||
if (typeof queryResult.data === "string") {
|
||||
result = JSON.parse(
|
||||
Buffer.from(queryResult.data, "base64").toString("utf-8")
|
||||
);
|
||||
return {
|
||||
isWrapped: true,
|
||||
chainId: result.asset_chain,
|
||||
assetAddress: new Uint8Array(
|
||||
Buffer.from(result.asset_address, "base64")
|
||||
),
|
||||
};
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("getOriginalAssetInjective() failed:", e);
|
||||
}
|
||||
return {
|
||||
isWrapped: false,
|
||||
chainId: chainId,
|
||||
assetAddress: hexToUint8Array(buildTokenId(chainId, wrappedAddress)),
|
||||
};
|
||||
}
|
||||
|
||||
export async function getOriginalAssetCosmWasm(
|
||||
client: LCDClient,
|
||||
wrappedAddress: string,
|
||||
lookupChain: ChainId | ChainName
|
||||
lookupChain: CosmWasmChainId | CosmWasmChainName
|
||||
): Promise<WormholeWrappedInfo> {
|
||||
const chainId = coalesceChainId(lookupChain);
|
||||
if (isNativeDenom(wrappedAddress)) {
|
||||
const chainId = coalesceCosmWasmChainId(lookupChain);
|
||||
if (isNativeCosmWasmDenom(chainId, wrappedAddress)) {
|
||||
return {
|
||||
isWrapped: false,
|
||||
chainId: chainId,
|
||||
assetAddress:
|
||||
chainId === CHAIN_ID_TERRA
|
||||
? buildNativeId(wrappedAddress)
|
||||
: hexToUint8Array(buildTokenId(wrappedAddress)),
|
||||
: hexToUint8Array(buildTokenId(chainId, wrappedAddress)),
|
||||
};
|
||||
}
|
||||
try {
|
||||
|
@ -121,7 +182,7 @@ export async function getOriginalAssetCosmWasm(
|
|||
assetAddress:
|
||||
chainId === CHAIN_ID_TERRA
|
||||
? zeroPad(canonicalAddress(wrappedAddress), 32)
|
||||
: hexToUint8Array(buildTokenId(wrappedAddress)),
|
||||
: hexToUint8Array(buildTokenId(chainId, wrappedAddress)),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -22,22 +22,19 @@ import {
|
|||
MAX_VAA_DECIMALS,
|
||||
WSOL_ADDRESS,
|
||||
WSOL_DECIMALS,
|
||||
uint8ArrayToHex
|
||||
uint8ArrayToHex,
|
||||
} from "../utils";
|
||||
|
||||
import {
|
||||
getForeignAssetNear
|
||||
} from ".";
|
||||
import { getForeignAssetNear } from ".";
|
||||
|
||||
import {
|
||||
_parseVAAAlgorand,
|
||||
} from "../algorand";
|
||||
import { _parseVAAAlgorand } from "../algorand";
|
||||
|
||||
import { hexToNativeString } from "../utils/array";
|
||||
import { parseTransferPayload } from "../utils/parseVaa";
|
||||
import { Account as nearAccount } from "near-api-js";
|
||||
import BN from "bn.js";
|
||||
import { providers as nearProviders } from "near-api-js";
|
||||
import { MsgExecuteContract as MsgExecuteContractInjective } from "@injectivelabs/sdk-ts";
|
||||
|
||||
export async function redeemOnEth(
|
||||
tokenBridgeAddress: string,
|
||||
|
@ -75,6 +72,29 @@ export async function redeemOnTerra(
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits the supplied VAA to Injective
|
||||
* @param tokenBridgeAddress Address of Inj token bridge contract
|
||||
* @param walletAddress Address of wallet in inj format
|
||||
* @param signedVAA VAA with the attestation message
|
||||
* @returns Message to be broadcast
|
||||
*/
|
||||
export async function submitVAAOnInjective(
|
||||
tokenBridgeAddress: string,
|
||||
walletAddress: string,
|
||||
signedVAA: Uint8Array
|
||||
): Promise<MsgExecuteContractInjective> {
|
||||
return MsgExecuteContractInjective.fromJSON({
|
||||
contractAddress: tokenBridgeAddress,
|
||||
sender: walletAddress,
|
||||
msg: {
|
||||
data: fromUint8Array(signedVAA),
|
||||
},
|
||||
action: "submit_vaa",
|
||||
});
|
||||
}
|
||||
export const redeemOnInjective = submitVAAOnInjective;
|
||||
|
||||
export async function redeemAndUnwrapOnSolana(
|
||||
connection: Connection,
|
||||
bridgeAddress: string,
|
||||
|
|
|
@ -7,6 +7,7 @@ import {
|
|||
Transaction as SolanaTransaction,
|
||||
} from "@solana/web3.js";
|
||||
import { MsgExecuteContract } from "@terra-money/terra.js";
|
||||
import { MsgExecuteContract as MsgExecuteContractInjective } from "@injectivelabs/sdk-ts";
|
||||
import {
|
||||
Algodv2,
|
||||
bigIntToBytes,
|
||||
|
@ -18,7 +19,7 @@ import {
|
|||
SuggestedParams,
|
||||
Transaction as AlgorandTransaction,
|
||||
} from "algosdk";
|
||||
import { BigNumber, ethers, Overrides, PayableOverrides } from "ethers";
|
||||
import { ethers, Overrides, PayableOverrides } from "ethers";
|
||||
import { isNativeDenom } from "..";
|
||||
import {
|
||||
assetOptinCheck,
|
||||
|
@ -34,7 +35,6 @@ import {
|
|||
import { getBridgeFeeIx, ixFromRust } from "../solana";
|
||||
import { importTokenWasm } from "../solana/wasm";
|
||||
import {
|
||||
CHAIN_ID_SOLANA,
|
||||
ChainId,
|
||||
ChainName,
|
||||
WSOL_ADDRESS,
|
||||
|
@ -43,9 +43,14 @@ import {
|
|||
hexToUint8Array,
|
||||
textToUint8Array,
|
||||
uint8ArrayToHex,
|
||||
CHAIN_ID_SOLANA,
|
||||
} from "../utils";
|
||||
import { safeBigIntToNumber } from "../utils/bigint";
|
||||
import { Account as nearAccount, providers as nearProviders } from "near-api-js";
|
||||
import { isNativeDenomInjective } from "../cosmwasm";
|
||||
import {
|
||||
Account as nearAccount,
|
||||
providers as nearProviders,
|
||||
} from "near-api-js";
|
||||
import { parseSequenceFromLogNear } from "../bridge/parseSequenceFromLog";
|
||||
|
||||
const BN = require("bn.js");
|
||||
|
@ -239,6 +244,95 @@ export async function transferFromTerra(
|
|||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the necessary messages to transfer an asset
|
||||
* @param walletAddress Address of the Inj wallet
|
||||
* @param tokenBridgeAddress Address of the token bridge contract
|
||||
* @param tokenAddress Address of the token being transferred
|
||||
* @param amount Amount of token to be transferred
|
||||
* @param recipientChain Destination chain
|
||||
* @param recipientAddress Destination wallet address
|
||||
* @param relayerFee Relayer fee
|
||||
* @param payload Optional payload
|
||||
* @returns Transfer messages to be sent on chain
|
||||
*/
|
||||
export async function transferFromInjective(
|
||||
walletAddress: string,
|
||||
tokenBridgeAddress: string,
|
||||
tokenAddress: string,
|
||||
amount: string,
|
||||
recipientChain: ChainId | ChainName,
|
||||
recipientAddress: Uint8Array,
|
||||
relayerFee: string = "0",
|
||||
payload: Uint8Array | null = null
|
||||
) {
|
||||
const recipientChainId = coalesceChainId(recipientChain);
|
||||
const nonce = Math.round(Math.random() * 100000);
|
||||
const isNativeAsset = isNativeDenomInjective(tokenAddress);
|
||||
const mk_action: string = payload
|
||||
? "initiate_transfer_with_payload"
|
||||
: "initiate_transfer";
|
||||
const mk_initiate_transfer = (info: object) =>
|
||||
payload
|
||||
? {
|
||||
asset: {
|
||||
amount,
|
||||
info,
|
||||
},
|
||||
recipient_chain: recipientChainId,
|
||||
recipient: Buffer.from(recipientAddress).toString("base64"),
|
||||
fee: relayerFee,
|
||||
nonce: nonce,
|
||||
payload: payload,
|
||||
}
|
||||
: {
|
||||
asset: {
|
||||
amount,
|
||||
info,
|
||||
},
|
||||
recipient_chain: recipientChainId,
|
||||
recipient: Buffer.from(recipientAddress).toString("base64"),
|
||||
fee: relayerFee,
|
||||
nonce: nonce,
|
||||
};
|
||||
return isNativeAsset
|
||||
? [
|
||||
MsgExecuteContractInjective.fromJSON({
|
||||
contractAddress: tokenBridgeAddress,
|
||||
sender: walletAddress,
|
||||
msg: {},
|
||||
action: "deposit_tokens",
|
||||
amount: { denom: tokenAddress, amount: amount },
|
||||
}),
|
||||
MsgExecuteContractInjective.fromJSON({
|
||||
contractAddress: tokenBridgeAddress,
|
||||
sender: walletAddress,
|
||||
msg: mk_initiate_transfer({ native_token: { denom: tokenAddress } }),
|
||||
action: mk_action,
|
||||
}),
|
||||
]
|
||||
: [
|
||||
MsgExecuteContractInjective.fromJSON({
|
||||
contractAddress: tokenBridgeAddress,
|
||||
sender: walletAddress,
|
||||
msg: {
|
||||
spender: tokenBridgeAddress,
|
||||
amount: amount,
|
||||
expires: {
|
||||
never: {},
|
||||
},
|
||||
},
|
||||
action: "increase_allowance",
|
||||
}),
|
||||
MsgExecuteContractInjective.fromJSON({
|
||||
contractAddress: tokenBridgeAddress,
|
||||
sender: walletAddress,
|
||||
msg: mk_initiate_transfer({ token: { contract_addr: tokenAddress } }),
|
||||
action: mk_action,
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
export async function transferNativeSol(
|
||||
connection: Connection,
|
||||
bridgeAddress: string,
|
||||
|
@ -634,7 +728,7 @@ export async function transferFromAlgorand(
|
|||
/**
|
||||
* Transfers an asset from Near to a receiver on another chain
|
||||
* @param client
|
||||
* @param coreBridge account
|
||||
* @param coreBridge account
|
||||
* @param tokenBridge account of the token bridge
|
||||
* @param assetId account
|
||||
* @param qty Quantity to transfer
|
||||
|
@ -659,7 +753,7 @@ export async function transferTokenFromNear(
|
|||
|
||||
let result;
|
||||
|
||||
let message_fee = (await client.viewFunction(coreBridge, "message_fee", {}));
|
||||
let message_fee = await client.viewFunction(coreBridge, "message_fee", {});
|
||||
|
||||
if (wormhole) {
|
||||
result = await client.functionCall({
|
||||
|
@ -696,7 +790,9 @@ export async function transferTokenFromNear(
|
|||
}
|
||||
|
||||
if (message_fee > 0) {
|
||||
let bank = await client.viewFunction(tokenBridge, "bank_balance", { acct: client.accountId });
|
||||
let bank = await client.viewFunction(tokenBridge, "bank_balance", {
|
||||
acct: client.accountId,
|
||||
});
|
||||
|
||||
if (!bank[0]) {
|
||||
await client.functionCall({
|
||||
|
@ -744,7 +840,7 @@ export async function transferTokenFromNear(
|
|||
/**
|
||||
* Transfers NEAR from Near to a receiver on another chain
|
||||
* @param client
|
||||
* @param coreBridge account
|
||||
* @param coreBridge account
|
||||
* @param tokenBridge account of the token bridge
|
||||
* @param qty Quantity to transfer
|
||||
* @param receiver Receiving account
|
||||
|
@ -775,7 +871,7 @@ export async function transferNearFromNear(
|
|||
payload: payload,
|
||||
message_fee: message_fee,
|
||||
},
|
||||
attachedDeposit: (new BN(qty.toString(10)).add(new BN(message_fee))),
|
||||
attachedDeposit: new BN(qty.toString(10)).add(new BN(message_fee)),
|
||||
gas: new BN("100000000000000"),
|
||||
});
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import {
|
|||
createWrappedOnSolana,
|
||||
createWrappedOnTerra,
|
||||
createWrappedOnNear,
|
||||
submitVAAOnInjective,
|
||||
} from ".";
|
||||
import { Bridge__factory } from "../ethers-contracts";
|
||||
|
||||
|
@ -21,6 +22,8 @@ export async function updateWrappedOnEth(
|
|||
|
||||
export const updateWrappedOnTerra = createWrappedOnTerra;
|
||||
|
||||
export const updateWrappedOnInjective = submitVAAOnInjective;
|
||||
|
||||
export const updateWrappedOnSolana = createWrappedOnSolana;
|
||||
|
||||
export const updateWrappedOnAlgorand = createWrappedOnAlgorand;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { expect, test } from "@jest/globals";
|
||||
import { zeroPad } from "ethers/lib/utils";
|
||||
import { canonicalAddress } from "../cosmos";
|
||||
import { tryUint8ArrayToNative, tryNativeToHexString } from "./array";
|
||||
|
@ -31,3 +32,11 @@ test("wormchain address conversion", () => {
|
|||
|
||||
expect(tryNativeToHexString(human, "wormholechain")).toBe(canonical);
|
||||
});
|
||||
|
||||
test("injective address conversion", () => {
|
||||
const human = "inj180rl9ezc4389t72pc3vvlkxxs5d9jx60w9eeu3";
|
||||
const canonical = canonicalAddress(human);
|
||||
const lpadCanonical = zeroPad(canonical, 32);
|
||||
const native = tryUint8ArrayToNative(lpadCanonical, "injective");
|
||||
expect(native).toBe(human);
|
||||
});
|
||||
|
|
|
@ -88,6 +88,8 @@ export const tryUint8ArrayToNative = (
|
|||
}
|
||||
return humanAddress("terra", a.slice(-20));
|
||||
}
|
||||
} else if (chainId === CHAIN_ID_INJECTIVE) {
|
||||
return humanAddress("inj", a.slice(-20));
|
||||
} else if (chainId === CHAIN_ID_ALGORAND) {
|
||||
return uint8ArrayToNativeStringAlgorand(a);
|
||||
} else if (chainId == CHAIN_ID_WORMHOLE_CHAIN) {
|
||||
|
@ -95,8 +97,6 @@ export const tryUint8ArrayToNative = (
|
|||
return humanAddress("wormhole", a.slice(-20));
|
||||
} else if (chainId === CHAIN_ID_NEAR) {
|
||||
throw Error("uint8ArrayToNative: Near not supported yet.");
|
||||
} else if (chainId === CHAIN_ID_INJECTIVE) {
|
||||
throw Error("uint8ArrayToNative: Injective not supported yet.");
|
||||
} else if (chainId === CHAIN_ID_OSMOSIS) {
|
||||
throw Error("uint8ArrayToNative: Osmosis not supported yet.");
|
||||
} else if (chainId === CHAIN_ID_SUI) {
|
||||
|
@ -207,16 +207,16 @@ export const tryNativeToHexString = (
|
|||
} else {
|
||||
return uint8ArrayToHex(zeroPad(canonicalAddress(address), 32));
|
||||
}
|
||||
} else if (chainId === CHAIN_ID_TERRA2) {
|
||||
return buildTokenId(address);
|
||||
} else if (chainId === CHAIN_ID_TERRA2 || chainId === CHAIN_ID_INJECTIVE) {
|
||||
return buildTokenId(chainId, address);
|
||||
} else if (chainId === CHAIN_ID_ALGORAND) {
|
||||
return nativeStringToHexAlgorand(address);
|
||||
} else if (chainId == CHAIN_ID_WORMHOLE_CHAIN) {
|
||||
return uint8ArrayToHex(zeroPad(canonicalAddress(address), 32));
|
||||
} else if (chainId === CHAIN_ID_NEAR) {
|
||||
return uint8ArrayToHex(zeroPad(new Uint8Array(Buffer.from(address, "ascii")), 32))
|
||||
} else if (chainId === CHAIN_ID_INJECTIVE) {
|
||||
throw Error("hexToNativeString: Injective not supported yet.");
|
||||
return uint8ArrayToHex(
|
||||
zeroPad(new Uint8Array(Buffer.from(address, "ascii")), 32)
|
||||
);
|
||||
} else if (chainId === CHAIN_ID_OSMOSIS) {
|
||||
throw Error("hexToNativeString: Osmosis not supported yet.");
|
||||
} else if (chainId === CHAIN_ID_SUI) {
|
||||
|
|
|
@ -55,14 +55,13 @@ export type EVMChainName =
|
|||
| "optimism"
|
||||
| "gnosis"
|
||||
| "ropsten";
|
||||
/**
|
||||
/**
|
||||
*
|
||||
* All the Solana-based chain names that Wormhole supports
|
||||
*/
|
||||
export type SolanaChainName =
|
||||
| "solana"
|
||||
| "pythnet";
|
||||
export type SolanaChainName = "solana" | "pythnet";
|
||||
|
||||
export type CosmWasmChainName = "terra" | "terra2" | "injective";
|
||||
export type TerraChainName = "terra" | "terra2";
|
||||
|
||||
export type Contracts = {
|
||||
|
@ -306,12 +305,12 @@ const TESTNET = {
|
|||
nft_bridge: undefined,
|
||||
},
|
||||
injective: {
|
||||
core: undefined,
|
||||
token_bridge: undefined,
|
||||
core: "inj1xx3aupmgv3ce537c0yce8zzd3sz567syuyedpg",
|
||||
token_bridge: "inj1q0e70vhrv063eah90mu97sazhywmeegp7myvnh",
|
||||
nft_bridge: undefined,
|
||||
},
|
||||
osmosis: {
|
||||
core: undefined,
|
||||
core: "osmo1hggkxr0hpw83f8vuft7ruvmmamsxmwk2hzz6nytdkzyup9krt0dq27sgyx",
|
||||
token_bridge: undefined,
|
||||
nft_bridge: undefined,
|
||||
},
|
||||
|
@ -608,8 +607,9 @@ export const CHAIN_ID_TO_NAME: ChainIdToName = Object.entries(CHAINS).reduce(
|
|||
*/
|
||||
export type EVMChainId = typeof CHAINS[EVMChainName];
|
||||
|
||||
export type TerraChainId = typeof CHAINS[TerraChainName];
|
||||
export type CosmWasmChainId = typeof CHAINS[CosmWasmChainName];
|
||||
|
||||
export type TerraChainId = typeof CHAINS[TerraChainName];
|
||||
/**
|
||||
*
|
||||
* Returns true when called with a valid chain, and narrows the type in the
|
||||
|
@ -662,6 +662,22 @@ export function toChainName(chainId: ChainId): ChainName {
|
|||
return CHAIN_ID_TO_NAME[chainId];
|
||||
}
|
||||
|
||||
export function toCosmWasmChainId(
|
||||
chainName: CosmWasmChainName
|
||||
): CosmWasmChainId {
|
||||
return CHAINS[chainName];
|
||||
}
|
||||
|
||||
export function coalesceCosmWasmChainId(
|
||||
chain: CosmWasmChainId | CosmWasmChainName
|
||||
): CosmWasmChainId {
|
||||
// this is written in a way that for invalid inputs (coming from vanilla
|
||||
// javascript or someone doing type casting) it will always return undefined.
|
||||
return typeof chain === "number" && isCosmWasmChain(chain)
|
||||
? chain
|
||||
: toCosmWasmChainId(chain);
|
||||
}
|
||||
|
||||
export function coalesceChainId(chain: ChainId | ChainName): ChainId {
|
||||
// this is written in a way that for invalid inputs (coming from vanilla
|
||||
// javascript or someone doing type casting) it will always return undefined.
|
||||
|
@ -710,6 +726,17 @@ export function isEVMChain(
|
|||
}
|
||||
}
|
||||
|
||||
export function isCosmWasmChain(
|
||||
chain: ChainId | ChainName
|
||||
): chain is CosmWasmChainId | CosmWasmChainName {
|
||||
const chainId = coalesceChainId(chain);
|
||||
return (
|
||||
chainId === CHAIN_ID_TERRA ||
|
||||
chainId === CHAIN_ID_TERRA2 ||
|
||||
chainId === CHAIN_ID_INJECTIVE
|
||||
);
|
||||
}
|
||||
|
||||
export function isTerraChain(
|
||||
chain: ChainId | ChainName
|
||||
): chain is TerraChainId | TerraChainName {
|
||||
|
|
Loading…
Reference in New Issue