wormhole/near/test/transferFromNear.ts

171 lines
4.8 KiB
TypeScript

// Prerequisites
// cd ethereum && npm ci
// cd sdk/js && npm ci && npm run build
// cd near
// npm ci
// Run with
// ETH_ADDRESS="" NEAR_TOKEN="" TOKENS_TO_SEND="" NEAR_MNEMONIC="" NEAR_ACCOUNT="" npm run transferFromNear
// or
// ETH_ADDRESS="" NEAR_TOKEN="" TOKENS_TO_SEND="" NEAR_PK="" NEAR_ACCOUNT="" npm run transferFromNear
// It is SUPER SUPER important to use the near-api-js that comes from inside wormhole-sdk or all heck breaks lose
import {
Account as nearAccount,
connect as nearConnect,
keyStores as nearKeyStores,
utils as nearUtils,
} from "@certusone/wormhole-sdk/node_modules/near-api-js";
import {
CHAIN_ID_ETH,
CHAIN_ID_NEAR,
CONTRACTS,
getEmitterAddressEth,
getEmitterAddressNear,
getSignedVAAWithRetry,
hexToUint8Array,
parseSequenceFromLogNear,
transferTokenFromNear,
uint8ArrayToHex,
} from "@certusone/wormhole-sdk";
import { NodeHttpTransport } from "@improbable-eng/grpc-web-node-http-transport";
// @ts-ignore
import { parseSeedPhrase } from "near-seed-phrase";
import colors from "@colors/colors/safe";
import prompt from "prompt";
export const WORMHOLE_RPC_HOSTS = [
"https://wormhole-v2-mainnet-api.certus.one",
"https://wormhole.inotel.ro",
"https://wormhole-v2-mainnet-api.mcf.rocks",
"https://wormhole-v2-mainnet-api.chainlayer.network",
"https://wormhole-v2-mainnet-api.staking.fund",
"https://wormhole-v2-mainnet.01node.com",
];
if (!process.env.ETH_ADDRESS) {
console.log("ETH_ADDRESS is required");
process.exit(1);
}
if (!process.env.NEAR_TOKEN) {
console.log("NEAR_TOKEN is required");
process.exit(1);
}
if (!process.env.NEAR_ACCOUNT) {
console.log("NEAR_ACCOUNT is required");
process.exit(1);
}
if (!process.env.TOKENS_TO_SEND) {
console.log("TOKENS_TO_SEND is required");
process.exit(1);
}
const YOUR_ETH_ADDRESS_HERE = getEmitterAddressEth(process.env.ETH_ADDRESS);
const NEAR_TOKEN_ADDRESS: string = process.env.NEAR_TOKEN;
const TOKENS_TO_SEND: bigint = BigInt(process.env.TOKENS_TO_SEND);
async function transferTest() {
let nearNodeUrl = "https://rpc.mainnet.near.org";
let networkId = "mainnet";
// There are many kinds of keystores... in this case, I am using a InMemory one
let keyStore = new nearKeyStores.InMemoryKeyStore();
if (process.env.NEAR_MNEMONIC) {
let userKeys = parseSeedPhrase(process.env.NEAR_MNEMONIC);
let userKey = nearUtils.KeyPair.fromString(userKeys["secretKey"]);
keyStore.setKey(networkId, process.env.NEAR_ACCOUNT as string, userKey);
} else if (process.env.NEAR_PK) {
let userKey = nearUtils.KeyPair.fromString(process.env.NEAR_PK);
keyStore.setKey(networkId, process.env.NEAR_ACCOUNT as string, userKey);
} else {
console.log("NEAR_MNEMONIC or NEAR_PK is required");
process.exit(1);
}
// connect to near...
let near = await nearConnect({
headers: {},
keyStore,
networkId: networkId as string,
nodeUrl: nearNodeUrl as string,
});
console.log(
"Sending",
TOKENS_TO_SEND.toString(),
NEAR_TOKEN_ADDRESS,
"from",
process.env.NEAR_ACCOUNT as string,
"to",
YOUR_ETH_ADDRESS_HERE,
"on Ethereum"
);
prompt.message = "";
const { input } = await prompt.get({
properties: {
input: {
description: colors.red(
"Are you sure you want to send tokens? THIS CANNOT BE UNDONE! [y/N]"
),
},
},
});
if (input !== "y") return;
// rpc handle
const userAccount = new nearAccount(
near.connection,
process.env.NEAR_ACCOUNT as string
);
const provider = userAccount.connection.provider;
const transferMsgs = await transferTokenFromNear(
provider,
userAccount.accountId,
CONTRACTS.MAINNET.near.core,
CONTRACTS.MAINNET.near.token_bridge,
NEAR_TOKEN_ADDRESS,
TOKENS_TO_SEND,
hexToUint8Array(YOUR_ETH_ADDRESS_HERE),
CHAIN_ID_ETH,
BigInt(0)
);
let transferOutcome;
for (const msg of transferMsgs) {
transferOutcome = await userAccount.functionCall(msg);
}
const sequence = parseSequenceFromLogNear(transferOutcome);
if (sequence === null) {
console.log("No sequence found, check above for error");
process.exit(1);
}
const emitterAddress = getEmitterAddressNear(
CONTRACTS.MAINNET.near.token_bridge
);
console.log("emitterAddress:", emitterAddress, "sequence:", sequence);
console.log(
`If this script hangs, try https://wormhole-v2-mainnet-api.certus.one/v1/signed_vaa/15/${emitterAddress}/${sequence.toString()}`
);
const { vaaBytes: signedVAA } = await getSignedVAAWithRetry(
WORMHOLE_RPC_HOSTS,
CHAIN_ID_NEAR,
emitterAddress,
sequence.toString(),
{
transport: NodeHttpTransport(),
}
);
console.log("Redeem this on https://www.portalbridge.com/#/redeem");
console.log(`Expand "Advanced" and paste this Signed VAA`);
console.log(uint8ArrayToHex(signedVAA));
}
transferTest();