ci: add github workflow with prettier checks for clients/js/src and sdk/js/src (#3176)

* github: add prettier check for clients/js

* github: update workflow to include sdk/js
This commit is contained in:
Paul Noel 2023-07-12 15:30:14 +00:00 committed by GitHub
parent f5987a334f
commit 6309b321e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 1208 additions and 1070 deletions

View File

@ -394,3 +394,11 @@ jobs:
uses: actions/checkout@v2
- run: chmod 755 ./scripts/check-npm-package-scopes.sh
- run: ./scripts/check-npm-package-scopes.sh
prettier:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 16
- run: npx prettier --check ./clients/js/src ./sdk/js/src

1
.prettierignore Normal file
View File

@ -0,0 +1 @@
sdk/js/src/ethers-contracts

View File

@ -115,7 +115,7 @@ export async function execute_algorand(
break;
}
case "WormholeRelayer":
throw Error("Wormhole Relayer not supported on Algorand");
throw Error("Wormhole Relayer not supported on Algorand");
default:
target_contract = impossible(payload);
}

View File

@ -120,7 +120,7 @@ export const submit = async (
break;
}
case "WormholeRelayer":
throw Error("Wormhole Relayer not supported on Sei");
throw Error("Wormhole Relayer not supported on Sei");
default:
target_contract = impossible(payload);
execute_msg = impossible(payload);

View File

@ -199,7 +199,7 @@ export const submit = async (
break;
}
case "WormholeRelayer":
throw Error("Wormhole Relayer not supported on Sui");
throw Error("Wormhole Relayer not supported on Sui");
default:
impossible(payload);
}

View File

@ -311,14 +311,14 @@ export const isSameType = (a: string, b: string) => {
export const isSuiCreateEvent = <
T extends NonNullable<SuiTransactionBlockResponse["objectChanges"]>[number],
K extends Extract<T, { type: "created" }>
K extends Extract<T, { type: "created" }>,
>(
event: T
): event is K => event?.type === "created";
export const isSuiPublishEvent = <
T extends NonNullable<SuiTransactionBlockResponse["objectChanges"]>[number],
K extends Extract<T, { type: "published" }>
K extends Extract<T, { type: "published" }>,
>(
event: T
): event is K => event?.type === "published";

View File

@ -82,8 +82,7 @@ export const builder = function (y: typeof yargs) {
describe: "Module to register",
choices: ["NFTBridge", "TokenBridge", "WormholeRelayer"],
demandOption: true,
} as const)
,
} as const),
(argv) => {
const module = argv["module"];
assertChain(argv.chain);
@ -272,7 +271,7 @@ export const builder = function (y: typeof yargs) {
describe: "Address of the delivery provider contract",
type: "string",
demandOption: true,
})
});
},
(argv) => {
assertChain(argv.chain);
@ -280,7 +279,10 @@ export const builder = function (y: typeof yargs) {
module: "WormholeRelayer",
type: "SetDefaultDeliveryProvider",
chain: toChainId(argv["chain"]),
relayProviderAddress: parseAddress(argv["chain"], argv["delivery-provider-address"])
relayProviderAddress: parseAddress(
argv["chain"],
argv["delivery-provider-address"]
),
};
let v = makeVAA(
GOVERNANCE_CHAIN,

View File

@ -2,12 +2,8 @@ import {
CHAINS,
ChainName,
assertChain,
} from "@certusone/wormhole-sdk/lib/esm/utils/consts";
import {
relayer,
Network
} from "@certusone/wormhole-sdk"
import { relayer, Network } from "@certusone/wormhole-sdk";
import yargs from "yargs";
import { CONTRACTS, NETWORKS } from "../consts";
import { assertNetwork } from "../utils";
@ -15,7 +11,8 @@ import { impossible } from "../vaa";
import { ethers } from "ethers";
export const command = "status <network> <chain> <tx>";
export const desc = "Prints information about the automatic delivery initiated on the specified network, chain, and tx";
export const desc =
"Prints information about the automatic delivery initiated on the specified network, chain, and tx";
export const builder = (y: typeof yargs) =>
y
.positional("network", {
@ -40,8 +37,9 @@ export const handler = async (
assertNetwork(network);
const chain = argv.chain;
assertChain(chain);
const addr = relayer.RELAYER_CONTRACTS[network][chain]?.wormholeRelayerAddress;
const addr =
relayer.RELAYER_CONTRACTS[network][chain]?.wormholeRelayerAddress;
if (!addr) {
throw new Error(`Wormhole Relayer not deployed on ${chain} in ${network}`);
}
@ -49,11 +47,20 @@ export const handler = async (
const sourceRPC = NETWORKS[network as Network][chain as ChainName].rpc;
const sourceChainProvider = new ethers.providers.JsonRpcProvider(sourceRPC);
const targetChainProviders = new Map<ChainName, ethers.providers.Provider>();
for(const key in NETWORKS[network]) {
targetChainProviders.set(key as ChainName, new ethers.providers.JsonRpcProvider(NETWORKS[network][key as ChainName].rpc));
for (const key in NETWORKS[network]) {
targetChainProviders.set(
key as ChainName,
new ethers.providers.JsonRpcProvider(
NETWORKS[network][key as ChainName].rpc
)
);
}
const info = await relayer.getWormholeRelayerInfo(chain, argv.tx, {environment: network, sourceChainProvider, targetChainProviders});
const info = await relayer.getWormholeRelayerInfo(chain, argv.tx, {
environment: network,
sourceChainProvider,
targetChainProviders,
});
console.log(relayer.stringifyWormholeRelayerInfo(info));
};

View File

@ -123,9 +123,8 @@ export const addSetupCommands: YargsAddCommandsFn = (y: typeof yargs) =>
// Get token bridge state object ID
const tokenBridgeStateObjectId = getCreatedObjects(
tokenBridgeInitRes
).find((e) =>
isSameType(e.type, `${tokenBridgePackageId}::state::State`)
)?.objectId;
).find((e) => isSameType(e.type, `${tokenBridgePackageId}::state::State`))
?.objectId;
if (!tokenBridgeStateObjectId) {
throw new Error("Couldn't find token bridge state object ID.");
}

View File

@ -18,12 +18,11 @@ import * as sui from "./cmds/sui";
import * as verifyVaa from "./cmds/verifyVaa";
import * as status from "./cmds/status";
const MD_TAG = "<!--CLI_USAGE-->";
async function getHelpText(cmd: any): Promise<string> {
// Note that `yargs` is called as a function to produce a fresh copy.
// Otherwise the imported module is effectively a singleton where state from
// Otherwise the imported module is effectively a singleton where state from
// other commands is accumulated from repeat calls.
return await cmd.builder(yargs()).scriptName(`worm ${cmd.command}`).getHelp();
}
@ -41,14 +40,15 @@ async function getHelpText(cmd: any): Promise<string> {
submit,
sui,
verifyVaa,
status
status,
];
const helpOutputs: Buffer[] = [];
for (const cmd of cmds) {
const helpText = await getHelpText(cmd);
helpOutputs.push(Buffer.from(`
helpOutputs.push(
Buffer.from(`
<details>
<summary> ${cmd.command} </summary>
@ -56,11 +56,10 @@ async function getHelpText(cmd: any): Promise<string> {
${helpText}
\`\`\`
</details>
`))
`)
);
}
const f = fs.readFileSync("README.md");
const startIdx = f.indexOf(MD_TAG, 0);
const stopIdx = f.indexOf(MD_TAG, startIdx + 1);
@ -68,7 +67,7 @@ ${helpText}
const head = f.subarray(0, startIdx + MD_TAG.length);
const tail = f.subarray(stopIdx, f.length);
const content = Buffer.concat([head, ...helpOutputs, tail])
const content = Buffer.concat([head, ...helpOutputs, tail]);
fs.writeFileSync("README.md", content.toString())
fs.writeFileSync("README.md", content.toString());
})();

View File

@ -9,7 +9,7 @@ import {
getEmitterAddressEth,
getEmitterAddressNear,
getEmitterAddressSolana,
getEmitterAddressTerra
getEmitterAddressTerra,
} from "@certusone/wormhole-sdk/lib/esm/bridge/getEmitterAddress";
export async function getEmitterAddress(

View File

@ -29,10 +29,10 @@ console.warn = function (x: string) {
//
// eslint-disable-next-line @typescript-eslint/no-redeclare
interface BigInt {
/** Convert to BigInt to string form in JSON.stringify */
toJSON: () => string;
/** Convert to BigInt to string form in JSON.stringify */
toJSON: () => string;
}
// Without this JSON.stringify() blows up
(BigInt.prototype as any).toJSON = function () {
return this.toString();
return this.toString();
};

View File

@ -143,7 +143,7 @@ export async function execute_terra(
break;
}
case "WormholeRelayer":
throw Error("Wormhole Relayer not supported on Terra");
throw Error("Wormhole Relayer not supported on Terra");
default:
target_contract = impossible(payload);
execute_msg = impossible(payload);

File diff suppressed because it is too large Load Diff

View File

@ -139,7 +139,7 @@ export async function execute_xpla(
break;
}
case "WormholeRelayer":
throw Error("Wormhole Relayer not supported on Xpla");
throw Error("Wormhole Relayer not supported on Xpla");
default:
target_contract = impossible(payload);
execute_msg = impossible(payload);

View File

@ -5,7 +5,7 @@ import { ChainId } from "../../utils";
export const upgradeGuardianSet = (
coreBridgeAddress: string,
vaa: Uint8Array,
vaa: Uint8Array
): Types.EntryFunctionPayload => {
if (!coreBridgeAddress) throw new Error("Need core bridge address.");
return {
@ -22,12 +22,17 @@ export const initWormhole = (
chainId: ChainId,
governanceChainId: number,
governanceContract: Uint8Array,
initialGuardian: Uint8Array,
initialGuardian: Uint8Array
): Types.EntryFunctionPayload => {
if (!coreBridgeAddress) throw new Error("Need core bridge address.");
return {
function: `${coreBridgeAddress}::wormhole::init`,
type_arguments: [],
arguments: [chainId, governanceChainId, governanceContract, initialGuardian],
arguments: [
chainId,
governanceChainId,
governanceContract,
initialGuardian,
],
};
};

View File

@ -17,16 +17,16 @@ import {
export const attestToken = (
tokenBridgeAddress: string,
tokenChain: ChainId | ChainName,
tokenAddress: string,
tokenAddress: string
): Types.EntryFunctionPayload => {
if (!tokenBridgeAddress) throw new Error("Need token bridge address.");
const assetType = getAssetFullyQualifiedType(
tokenBridgeAddress,
coalesceChainId(tokenChain),
tokenAddress,
tokenAddress
);
if (!assetType) throw new Error("Invalid asset address.");
return {
function: `${tokenBridgeAddress}::attest_token::attest_token_entry`,
type_arguments: [assetType],
@ -40,7 +40,7 @@ export const completeTransfer = async (
client: AptosClient,
tokenBridgeAddress: string,
transferVAA: Uint8Array,
feeRecipient: string,
feeRecipient: string
): Promise<Types.EntryFunctionPayload> => {
if (!tokenBridgeAddress) throw new Error("Need token bridge address.");
@ -52,7 +52,7 @@ export const completeTransfer = async (
if (parsedVAA.ToChain !== CHAIN_ID_APTOS) {
throw new Error("Transfer is not destined for Aptos");
}
assertChain(parsedVAA.FromChain);
const assetType =
parsedVAA.FromChain === CHAIN_ID_APTOS
@ -78,7 +78,7 @@ export const completeTransfer = async (
export const completeTransferAndRegister = async (
client: AptosClient,
tokenBridgeAddress: string,
transferVAA: Uint8Array,
transferVAA: Uint8Array
): Promise<Types.EntryFunctionPayload> => {
if (!tokenBridgeAddress) throw new Error("Need token bridge address.");
@ -90,7 +90,7 @@ export const completeTransferAndRegister = async (
if (parsedVAA.ToChain !== CHAIN_ID_APTOS) {
throw new Error("Transfer is not destined for Aptos");
}
assertChain(parsedVAA.FromChain);
const assetType =
parsedVAA.FromChain === CHAIN_ID_APTOS
@ -117,21 +117,23 @@ export const completeTransferWithPayload = (
_tokenBridgeAddress: string,
_tokenChain: ChainId | ChainName,
_tokenAddress: string,
_vaa: Uint8Array,
_vaa: Uint8Array
): Types.EntryFunctionPayload => {
throw new Error("Completing transfers with payload is not yet supported in the sdk");
throw new Error(
"Completing transfers with payload is not yet supported in the sdk"
);
};
/**
* Construct a payload for a transaction that registers a coin defined by the given origin chain
* Construct a payload for a transaction that registers a coin defined by the given origin chain
* ID and address to the sender's account.
*
*
* The bytecode was compiled from the following Move code:
* ```move
* script {
* use aptos_framework::coin;
* use aptos_framework::signer;
*
*
* fun main<CoinType>(user: &signer) {
* if (!coin::is_account_registered<CoinType>(signer::address_of(user))) {
* coin::register<CoinType>(user);
@ -170,7 +172,9 @@ export const registerCoin = (
// Deploy coin
// don't need `signer` and `&signer` in argument list because the Move VM will inject them
export const deployCoin = (tokenBridgeAddress: string): Types.EntryFunctionPayload => {
export const deployCoin = (
tokenBridgeAddress: string
): Types.EntryFunctionPayload => {
if (!tokenBridgeAddress) throw new Error("Need token bridge address.");
return {
function: `${tokenBridgeAddress}::deploy_coin::deploy_coin`,
@ -183,7 +187,7 @@ export const deployCoin = (tokenBridgeAddress: string): Types.EntryFunctionPaylo
export const registerChain = (
tokenBridgeAddress: string,
vaa: Uint8Array,
vaa: Uint8Array
): Types.EntryFunctionPayload => {
if (!tokenBridgeAddress) throw new Error("Need token bridge address.");
return {

View File

@ -1,4 +1,7 @@
import { TransactionResponse, VersionedTransactionResponse } from "@solana/web3.js";
import {
TransactionResponse,
VersionedTransactionResponse,
} from "@solana/web3.js";
import { TxInfo } from "@terra-money/terra.js";
import { TxInfo as XplaTxInfo } from "@xpla/xpla.js";
import { AptosClient, Types } from "aptos";
@ -105,7 +108,9 @@ export function parseSequenceFromLogInjective(info: any): string {
}
const SOLANA_SEQ_LOG = "Program log: Sequence: ";
export function parseSequenceFromLogSolana(info: TransactionResponse | VersionedTransactionResponse) {
export function parseSequenceFromLogSolana(
info: TransactionResponse | VersionedTransactionResponse
) {
// TODO: better parsing, safer
const sequence = info.meta?.logMessages
?.filter((msg) => msg.startsWith(SOLANA_SEQ_LOG))?.[0]

View File

@ -16,6 +16,6 @@ export * as token_bridge from "./token_bridge";
export * as nft_bridge from "./nft_bridge";
export * as algorand from "./algorand";
export * as sui from "./sui";
export * as relayer from "./relayer"
export * as relayer from "./relayer";
export { postVaaSolana, postVaaSolanaWithRetry } from "./solana";

View File

@ -265,6 +265,4 @@ export class GovernanceEmitter extends MockEmitter {
uptickSequence
);
}
}

View File

@ -1,45 +1,52 @@
import { afterAll, beforeEach, describe, expect, jest, test} from "@jest/globals";
import {
afterAll,
beforeEach,
describe,
expect,
jest,
test,
} from "@jest/globals";
import { ethers } from "ethers";
import { DeliveryProvider__factory } from "../../ethers-contracts"
import {getAddressInfo} from "../consts"
import {getDefaultProvider} from "../relayer/helpers"
import {CHAINS, ChainId, ChainName, Network} from "../../../"
import {getNetwork, PRIVATE_KEY, isCI} from "./utils/utils";
import { DeliveryProvider__factory } from "../../ethers-contracts";
import { getAddressInfo } from "../consts";
import { getDefaultProvider } from "../relayer/helpers";
import { CHAINS, ChainId, ChainName, Network } from "../../../";
import { getNetwork, PRIVATE_KEY, isCI } from "./utils/utils";
const network: Network = getNetwork();
const ci: boolean = isCI();
const sourceChain = network == 'DEVNET' ? "ethereum" : "avalanche";
const targetChain = network == 'DEVNET' ? "bsc" : "celo";
const sourceChain = network == "DEVNET" ? "ethereum" : "avalanche";
const targetChain = network == "DEVNET" ? "bsc" : "celo";
const sourceChainId = CHAINS[sourceChain];
const targetChainId = CHAINS[targetChain];
describe("Relay Provider Test", () => {
const addressInfo = getAddressInfo(sourceChain, network);
const provider = getDefaultProvider(network, sourceChain, ci);
// signers
const oracleDeployer = new ethers.Wallet(PRIVATE_KEY, provider);
const deliveryProviderAddress = addressInfo.mockDeliveryProviderAddress;
if(!deliveryProviderAddress) throw Error("No relay provider address");
const deliveryProvider = DeliveryProvider__factory.connect(deliveryProviderAddress, oracleDeployer);
if (!deliveryProviderAddress) throw Error("No relay provider address");
const deliveryProvider = DeliveryProvider__factory.connect(
deliveryProviderAddress,
oracleDeployer
);
describe("Read Prices Correctly", () => {
test("readPrices", async () => {
const tokenPrice = ethers.BigNumber.from("100000");
const gasPrice = ethers.utils.parseUnits("300", "gwei");
const tokenPriceReturned = await deliveryProvider.nativeCurrencyPrice(targetChainId);
const tokenPriceReturned = await deliveryProvider.nativeCurrencyPrice(
targetChainId
);
const gasPriceReturned = await deliveryProvider.gasPrice(targetChainId);
expect(tokenPriceReturned.toString()).toBe(tokenPrice.toString());
expect(gasPriceReturned.toString()).toBe(gasPrice.toString());
});
});
});

View File

@ -1,26 +1,32 @@
import { Network } from "../../../utils";
import { PublicKey } from "@solana/web3.js";
import { ethers } from "ethers";
import {ETH_PRIVATE_KEY, Environment} from "../../../token_bridge/__tests__/utils/consts";
import {
ETH_PRIVATE_KEY,
Environment,
} from "../../../token_bridge/__tests__/utils/consts";
const SAFE_RELAY_DELAY = 10000;
const characters =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
export const PRIVATE_KEY = process.env['WALLET_KEY'] || ETH_PRIVATE_KEY;
export const PRIVATE_KEY = process.env["WALLET_KEY"] || ETH_PRIVATE_KEY;
export const networkOptions = ["MAINNET", "TESTNET", "DEVNET"];
export const isCI = (): boolean => {
return !!process.env['CI'];
}
return !!process.env["CI"];
};
export const getNetwork = (): Network => {
const network = process.env['NETWORK'] || "";
if(!(networkOptions.includes(network))) throw Error(`Invalid Network: ${network}. Options ${networkOptions.join(", ")}`);
return network as Network;
}
const network = process.env["NETWORK"] || "";
if (!networkOptions.includes(network))
throw Error(
`Invalid Network: ${network}. Options ${networkOptions.join(", ")}`
);
return network as Network;
};
export const generateRandomString = (length: number) => {
let randomString = "";
@ -36,7 +42,7 @@ export const getArbitraryBytes32 = (): string => {
return ethers.utils.hexlify(
ethers.utils.toUtf8Bytes(generateRandomString(32))
);
}
};
export async function waitForRelay(quantity?: number) {
await new Promise((resolve) =>
@ -45,36 +51,48 @@ export async function waitForRelay(quantity?: number) {
}
export const getGuardianRPC = (network: Network, ci: boolean) => {
return process.env.GUARDIAN_RPC || (ci ? "http://guardian:7071" : network == "DEVNET" ? "http://localhost:7071" : network == "TESTNET" ? "https://wormhole-v2-testnet-api.certus.one" : "https://wormhole-v2-mainnet-api.certus.one");
}
return (
process.env.GUARDIAN_RPC ||
(ci
? "http://guardian:7071"
: network == "DEVNET"
? "http://localhost:7071"
: network == "TESTNET"
? "https://wormhole-v2-testnet-api.certus.one"
: "https://wormhole-v2-mainnet-api.certus.one")
);
};
// These variables also live in testing/solana-test-validator/sdk-tests/helpers
// Ideally we find a better home for these (probably somewhere in the SDK)
// These are used to mock a devnet/CI guardian
export const GUARDIAN_KEYS = process.env.GUARDIAN_KEY ? [process.env.GUARDIAN_KEY] : [
"cfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0",
"c3b2e45c422a1602333a64078aeb42637370b0f48fe385f9cfa6ad54a8e0c47e",
"9f790d3f08bc4b5cd910d4278f3deb406e57bb5e924906ccd52052bb078ccd47",
"b20cc49d6f2c82a5e6519015fc18aa3e562867f85f872c58f1277cfbd2a0c8e4",
"eded5a2fdcb5bbbfa5b07f2a91393813420e7ac30a72fc935b6df36f8294b855",
"00d39587c3556f289677a837c7f3c0817cb7541ce6e38a243a4bdc761d534c5e",
"da534d61a8da77b232f3a2cee55c0125e2b3e33a5cd8247f3fe9e72379445c3b",
"cdbabfc2118eb00bc62c88845f3bbd03cb67a9e18a055101588ca9b36387006c",
"c83d36423820e7350428dc4abe645cb2904459b7d7128adefe16472fdac397ba",
"1cbf4e1388b81c9020500fefc83a7a81f707091bb899074db1bfce4537428112",
"17646a6ba14a541957fc7112cc973c0b3f04fce59484a92c09bb45a0b57eb740",
"eb94ff04accbfc8195d44b45e7c7da4c6993b2fbbfc4ef166a7675a905df9891",
"053a6527124b309d914a47f5257a995e9b0ad17f14659f90ed42af5e6e262b6a",
"3fbf1e46f6da69e62aed5670f279e818889aa7d8f1beb7fd730770fd4f8ea3d7",
"53b05697596ba04067e40be8100c9194cbae59c90e7870997de57337497172e9",
"4e95cb2ff3f7d5e963631ad85c28b1b79cb370f21c67cbdd4c2ffb0bf664aa06",
"01b8c448ce2c1d43cfc5938d3a57086f88e3dc43bb8b08028ecb7a7924f4676f",
"1db31a6ba3bcd54d2e8a64f8a2415064265d291593450c6eb7e9a6a986bd9400",
"70d8f1c9534a0ab61a020366b831a494057a289441c07be67e4288c44bc6cd5d",
];
export const GUARDIAN_SET_INDEX = process.env.GUARDIAN_SET_INDEX ? parseInt(process.env.GUARDIAN_SET_INDEX) : 0;
export const GOVERNANCE_EMITTER_ADDRESS = process.env.GOVERNANCE_EMITTER_ADDRESS || new PublicKey(
"11111111111111111111111111111115"
).toBuffer().toString("hex");
export const GUARDIAN_KEYS = process.env.GUARDIAN_KEY
? [process.env.GUARDIAN_KEY]
: [
"cfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0",
"c3b2e45c422a1602333a64078aeb42637370b0f48fe385f9cfa6ad54a8e0c47e",
"9f790d3f08bc4b5cd910d4278f3deb406e57bb5e924906ccd52052bb078ccd47",
"b20cc49d6f2c82a5e6519015fc18aa3e562867f85f872c58f1277cfbd2a0c8e4",
"eded5a2fdcb5bbbfa5b07f2a91393813420e7ac30a72fc935b6df36f8294b855",
"00d39587c3556f289677a837c7f3c0817cb7541ce6e38a243a4bdc761d534c5e",
"da534d61a8da77b232f3a2cee55c0125e2b3e33a5cd8247f3fe9e72379445c3b",
"cdbabfc2118eb00bc62c88845f3bbd03cb67a9e18a055101588ca9b36387006c",
"c83d36423820e7350428dc4abe645cb2904459b7d7128adefe16472fdac397ba",
"1cbf4e1388b81c9020500fefc83a7a81f707091bb899074db1bfce4537428112",
"17646a6ba14a541957fc7112cc973c0b3f04fce59484a92c09bb45a0b57eb740",
"eb94ff04accbfc8195d44b45e7c7da4c6993b2fbbfc4ef166a7675a905df9891",
"053a6527124b309d914a47f5257a995e9b0ad17f14659f90ed42af5e6e262b6a",
"3fbf1e46f6da69e62aed5670f279e818889aa7d8f1beb7fd730770fd4f8ea3d7",
"53b05697596ba04067e40be8100c9194cbae59c90e7870997de57337497172e9",
"4e95cb2ff3f7d5e963631ad85c28b1b79cb370f21c67cbdd4c2ffb0bf664aa06",
"01b8c448ce2c1d43cfc5938d3a57086f88e3dc43bb8b08028ecb7a7924f4676f",
"1db31a6ba3bcd54d2e8a64f8a2415064265d291593450c6eb7e9a6a986bd9400",
"70d8f1c9534a0ab61a020366b831a494057a289441c07be67e4288c44bc6cd5d",
];
export const GUARDIAN_SET_INDEX = process.env.GUARDIAN_SET_INDEX
? parseInt(process.env.GUARDIAN_SET_INDEX)
: 0;
export const GOVERNANCE_EMITTER_ADDRESS =
process.env.GOVERNANCE_EMITTER_ADDRESS ||
new PublicKey("11111111111111111111111111111115").toBuffer().toString("hex");

View File

@ -21,7 +21,7 @@ import {
VaaKey,
DeliveryOverrideArgs,
parseForwardFailureError,
parseRefundStatus
parseRefundStatus,
} from "../structs";
import {
DeliveryProvider,

View File

@ -19,7 +19,7 @@ export type SendOptionalParams = {
chainId?: ChainId;
emitterAddress: string;
sequenceNumber: ethers.BigNumberish;
}
},
];
deliveryProviderAddress?: string;
wormholeRelayerAddress?: string;

View File

@ -7,7 +7,7 @@ export enum RelayerPayloadId {
}
export enum ExecutionInfoVersion {
EVM_V1 = 0
EVM_V1 = 0,
}
export enum DeliveryStatus {
@ -26,16 +26,21 @@ export enum RefundStatus {
RefundFail = "Refund Fail",
CrossChainRefundSent = "Cross Chain Refund Sent",
CrossChainRefundFailProviderNotSupported = "Cross Chain Refund Fail - Provider does not support the refund chain",
CrossChainRefundFailNotEnough = "Cross Chain Refund Fail - Refund too low for cross chain refund"
CrossChainRefundFailNotEnough = "Cross Chain Refund Fail - Refund too low for cross chain refund",
}
export function parseRefundStatus(index: number) {
return index === 0 ? RefundStatus.RefundSent
: index === 1 ? RefundStatus.RefundFail
: index === 2 ? RefundStatus.CrossChainRefundSent
: index === 3 ? RefundStatus.CrossChainRefundFailProviderNotSupported
: index === 4 ? RefundStatus.CrossChainRefundFailNotEnough
: RefundStatus.CrossChainRefundFailProviderNotSupported;
return index === 0
? RefundStatus.RefundSent
: index === 1
? RefundStatus.RefundFail
: index === 2
? RefundStatus.CrossChainRefundSent
: index === 3
? RefundStatus.CrossChainRefundFailProviderNotSupported
: index === 4
? RefundStatus.CrossChainRefundFailNotEnough
: RefundStatus.CrossChainRefundFailProviderNotSupported;
}
export interface VaaKey {
@ -184,7 +189,7 @@ export function parseWormholeRelayerSend(bytes: Buffer): DeliveryInstruction {
refundDeliveryProvider,
sourceDeliveryProvider,
senderAddress,
vaaKeys: messages
vaaKeys: messages,
};
}
@ -200,23 +205,22 @@ function parseVaaKey(bytes: Buffer, idx: number): [VaaKey, number] {
const version = bytes.readUInt8(idx);
idx += 1;
const chainId = bytes.readUInt16BE(idx);
idx += 2;
const emitterAddress = bytes.slice(idx, idx + 32);
idx += 32;
const sequence = ethers.BigNumber.from(
Uint8Array.prototype.subarray.call(bytes, idx, idx + 8)
);
idx += 8;
return [
{
chainId,
emitterAddress,
sequence,
},
idx,
];
const chainId = bytes.readUInt16BE(idx);
idx += 2;
const emitterAddress = bytes.slice(idx, idx + 32);
idx += 32;
const sequence = ethers.BigNumber.from(
Uint8Array.prototype.subarray.call(bytes, idx, idx + 8)
);
idx += 8;
return [
{
chainId,
emitterAddress,
sequence,
},
idx,
];
}
export function parseEVMExecutionInfoV1(
@ -226,7 +230,7 @@ export function parseEVMExecutionInfoV1(
idx += 31;
const version = bytes.readUInt8(idx);
idx += 1;
if(version !== ExecutionInfoVersion.EVM_V1) {
if (version !== ExecutionInfoVersion.EVM_V1) {
throw new Error("Unexpected Execution Info version");
}
const gasLimit = ethers.BigNumber.from(
@ -267,11 +271,9 @@ export function parseWormholeRelayerResend(
let newEncodedExecutionInfo;
[newEncodedExecutionInfo, idx] = parsePayload(bytes, idx);
const newSourceDeliveryProvider = bytes.slice(idx, idx + 32);
idx += 32;
const newSenderAddress = bytes.slice(idx, idx + 32);
idx += 32;
return {
@ -280,14 +282,12 @@ export function parseWormholeRelayerResend(
newRequestedReceiverValue,
newEncodedExecutionInfo,
newSourceDeliveryProvider,
newSenderAddress
newSenderAddress,
};
}
export function executionInfoToString(
encodedExecutionInfo: Buffer
): string {
const [parsed,] = parseEVMExecutionInfoV1(encodedExecutionInfo, 0)
export function executionInfoToString(encodedExecutionInfo: Buffer): string {
const [parsed] = parseEVMExecutionInfoV1(encodedExecutionInfo, 0);
return `Gas limit: ${parsed.gasLimit}, Target chain refund per unit gas unused: ${parsed.targetChainRefundPerGasUnused}`;
}
@ -311,11 +311,11 @@ export function deliveryInstructionsPrintable(
}
export function vaaKeyPrintable(ix: VaaKey): StringLeaves<VaaKey> {
return {
chainId: ix.chainId?.toString(),
emitterAddress: ix.emitterAddress?.toString("hex"),
sequence: ix.sequence?.toString(),
};
return {
chainId: ix.chainId?.toString(),
emitterAddress: ix.emitterAddress?.toString("hex"),
sequence: ix.sequence?.toString(),
};
}
export function redeliveryInstructionPrintable(
@ -327,7 +327,7 @@ export function redeliveryInstructionPrintable(
newRequestedReceiverValue: ix.newRequestedReceiverValue.toString(),
newEncodedExecutionInfo: executionInfoToString(ix.newEncodedExecutionInfo),
newSourceDeliveryProvider: ix.newSourceDeliveryProvider.toString("hex"),
newSenderAddress: ix.newSenderAddress.toString("hex")
newSenderAddress: ix.newSenderAddress.toString("hex"),
};
}
@ -353,13 +353,11 @@ export function packOverrides(overrides: DeliveryOverrideArgs): string {
return "0x" + packed;
}
export function parseForwardFailureError(
bytes: Buffer
): string {
export function parseForwardFailureError(bytes: Buffer): string {
let idx = 4;
idx += 32;
if(bytes.length <= idx) {
return `Delivery Provider failed in performing forward`
if (bytes.length <= idx) {
return `Delivery Provider failed in performing forward`;
}
try {
const amountOfFunds = ethers.BigNumber.from(
@ -369,12 +367,12 @@ export function parseForwardFailureError(
const amountOfFundsNeeded = ethers.BigNumber.from(
Uint8Array.prototype.subarray.call(bytes, idx, idx + 32)
);
return `Not enough funds leftover for forward: Had ${ethers.utils.formatEther(amountOfFunds)} and needed ${ethers.utils.formatEther(amountOfFundsNeeded)}.`
return `Not enough funds leftover for forward: Had ${ethers.utils.formatEther(
amountOfFunds
)} and needed ${ethers.utils.formatEther(amountOfFundsNeeded)}.`;
} catch (err) {
return `Delivery Provider unexpectedly failed in performing forward`
return `Delivery Provider unexpectedly failed in performing forward`;
}
}
export function parseOverrideInfoFromDeliveryEvent(
@ -397,7 +395,7 @@ export function parseOverrideInfoFromDeliveryEvent(
return {
newReceiverValue,
newExecutionInfo,
redeliveryHash
redeliveryHash,
};
}

View File

@ -4,7 +4,9 @@ import { IdlEvent } from "../../anchor";
export class WormholeEventsCoder implements EventCoder {
constructor(_idl: Idl) {}
decode<E extends IdlEvent = IdlEvent, T = Record<string, string>>(_log: string): Event<E, T> | null {
decode<E extends IdlEvent = IdlEvent, T = Record<string, string>>(
_log: string
): Event<E, T> | null {
throw new Error("Wormhole program does not have events");
}
}

View File

@ -2,111 +2,111 @@
//
// https://github.com/coral-xyz/anchor/blob/master/ts/packages/anchor/src/coder/borsh/idl.ts
import * as borsh from "@coral-xyz/borsh"
import * as borsh from "@coral-xyz/borsh";
import { Layout } from "buffer-layout";
import { IdlField, IdlTypeDef } from "../../anchor";
import { camelCase } from "lodash";
export class IdlCoder {
public static fieldLayout(
field: { name?: string } & Pick<IdlField, "type">,
types?: IdlTypeDef[]
): Layout {
const fieldName =
field.name !== undefined ? camelCase(field.name) : undefined;
switch (field.type) {
case "bool": {
return borsh.bool(fieldName);
}
case "u8": {
return borsh.u8(fieldName);
}
case "i8": {
return borsh.i8(fieldName);
}
case "u16": {
return borsh.u16(fieldName);
}
case "i16": {
return borsh.i16(fieldName);
}
case "u32": {
return borsh.u32(fieldName);
}
case "i32": {
return borsh.i32(fieldName);
}
case "f32": {
return borsh.f32(fieldName);
}
case "u64": {
return borsh.u64(fieldName);
}
case "i64": {
return borsh.i64(fieldName);
}
case "f64": {
return borsh.f64(fieldName);
}
case "u128": {
return borsh.u128(fieldName);
}
case "i128": {
return borsh.i128(fieldName);
}
case "u256": {
return borsh.u256(fieldName);
}
case "i256": {
return borsh.i256(fieldName);
}
case "bytes": {
return borsh.vecU8(fieldName);
}
case "string": {
return borsh.str(fieldName);
}
case "publicKey": {
return borsh.publicKey(fieldName);
}
default: {
if ("vec" in field.type) {
return borsh.vec(
IdlCoder.fieldLayout(
{
name: undefined,
type: field.type.vec,
},
types
),
fieldName
);
} else if ("option" in field.type) {
return borsh.option(
IdlCoder.fieldLayout(
{
name: undefined,
type: field.type.option,
},
types
),
fieldName
);
} else if ("array" in field.type) {
let arrayTy = field.type.array[0];
let arrayLen = field.type.array[1];
let innerLayout = IdlCoder.fieldLayout(
public static fieldLayout(
field: { name?: string } & Pick<IdlField, "type">,
types?: IdlTypeDef[]
): Layout {
const fieldName =
field.name !== undefined ? camelCase(field.name) : undefined;
switch (field.type) {
case "bool": {
return borsh.bool(fieldName);
}
case "u8": {
return borsh.u8(fieldName);
}
case "i8": {
return borsh.i8(fieldName);
}
case "u16": {
return borsh.u16(fieldName);
}
case "i16": {
return borsh.i16(fieldName);
}
case "u32": {
return borsh.u32(fieldName);
}
case "i32": {
return borsh.i32(fieldName);
}
case "f32": {
return borsh.f32(fieldName);
}
case "u64": {
return borsh.u64(fieldName);
}
case "i64": {
return borsh.i64(fieldName);
}
case "f64": {
return borsh.f64(fieldName);
}
case "u128": {
return borsh.u128(fieldName);
}
case "i128": {
return borsh.i128(fieldName);
}
case "u256": {
return borsh.u256(fieldName);
}
case "i256": {
return borsh.i256(fieldName);
}
case "bytes": {
return borsh.vecU8(fieldName);
}
case "string": {
return borsh.str(fieldName);
}
case "publicKey": {
return borsh.publicKey(fieldName);
}
default: {
if ("vec" in field.type) {
return borsh.vec(
IdlCoder.fieldLayout(
{
name: undefined,
type: arrayTy,
type: field.type.vec,
},
types
);
return borsh.array(innerLayout, arrayLen, fieldName);
} else {
throw new Error(`Not yet implemented: ${field}`);
}
),
fieldName
);
} else if ("option" in field.type) {
return borsh.option(
IdlCoder.fieldLayout(
{
name: undefined,
type: field.type.option,
},
types
),
fieldName
);
} else if ("array" in field.type) {
let arrayTy = field.type.array[0];
let arrayLen = field.type.array[1];
let innerLayout = IdlCoder.fieldLayout(
{
name: undefined,
type: arrayTy,
},
types
);
return borsh.array(innerLayout, arrayLen, fieldName);
} else {
throw new Error(`Not yet implemented: ${field}`);
}
}
}
}
}
}

View File

@ -9,4 +9,4 @@ export class WormholeStateCoder implements StateCoder {
decode<T = any>(_ix: Buffer): T {
throw new Error("Wormhole program does not have state");
}
}
}

View File

@ -1,12 +1,12 @@
import { Idl, TypesCoder } from "@project-serum/anchor";
export class WormholeTypesCoder implements TypesCoder {
constructor(_idl: Idl) {}
encode<T = any>(_name: string, _type: T): Buffer {
throw new Error("Wormhole program does not have user-defined types");
}
decode<T = any>(_name: string, _typeData: Buffer): T {
throw new Error("Wormhole program does not have user-defined types");
}
}
constructor(_idl: Idl) {}
encode<T = any>(_name: string, _type: T): Buffer {
throw new Error("Wormhole program does not have user-defined types");
}
decode<T = any>(_name: string, _typeData: Buffer): T {
throw new Error("Wormhole program does not have user-defined types");
}
}

View File

@ -23,11 +23,9 @@ export function createInitializeInstruction(
): TransactionInstruction {
const methods = createReadOnlyWormholeProgramInterface(
wormholeProgramId
).methods.initialize(
guardianSetExpirationTime,
new BN(fee.toString()),
[...initialGuardians]
);
).methods.initialize(guardianSetExpirationTime, new BN(fee.toString()), [
...initialGuardians,
]);
// @ts-ignore
return methods._ixFn(...methods._args, {

View File

@ -70,7 +70,7 @@ export async function createVerifySignaturesInstructions(
for (let i = 0; i < Math.ceil(guardianSignatures.length / batchSize); ++i) {
const start = i * batchSize;
const end = Math.min(guardianSignatures.length, (i + 1) * batchSize);
const signatureStatus = new Array(MAX_LEN_GUARDIAN_KEYS).fill(-1);
const signatures: Buffer[] = [];
const keys: Buffer[] = [];
@ -123,9 +123,10 @@ function createVerifySignaturesInstruction(
signatureSet: PublicKeyInitData,
signatureStatus: number[]
): TransactionInstruction {
const methods = createReadOnlyWormholeProgramInterface(
wormholeProgramId
).methods.verifySignatures(signatureStatus);
const methods =
createReadOnlyWormholeProgramInterface(
wormholeProgramId
).methods.verifySignatures(signatureStatus);
// @ts-ignore
return methods._ixFn(...methods._args, {

View File

@ -109,7 +109,7 @@ export const tryUint8ArrayToNative = (
} else if (chainId === CHAIN_ID_XPLA) {
return humanAddress("xpla", a.slice(-20));
} else if (chainId === CHAIN_ID_SEI) {
return humanAddress("sei", a.slice(-20));
return humanAddress("sei", a.slice(-20));
} else if (chainId === CHAIN_ID_NEAR) {
throw Error("uint8ArrayToNative: Use tryHexToNativeStringNear instead.");
} else if (chainId === CHAIN_ID_OSMOSIS) {

View File

@ -63,12 +63,14 @@ export const EVMChainNames: ReadonlyArray<ChainName> = [
] as const;
export type EVMChainName = (typeof EVMChainNames)[number];
/*
*
* All the Solana-based chain names that Wormhole supports
*/
export const SolanaChainNames: ReadonlyArray<ChainName> = ["solana", "pythnet"] as const;
export const SolanaChainNames: ReadonlyArray<ChainName> = [
"solana",
"pythnet",
] as const;
export type SolanaChainName = (typeof SolanaChainNames)[number];
export const CosmWasmChainNames: ReadonlyArray<ChainName> = [
@ -81,7 +83,10 @@ export const CosmWasmChainNames: ReadonlyArray<ChainName> = [
export type CosmWasmChainName = (typeof CosmWasmChainNames)[number];
// TODO: why? these are dupe of entries in CosmWasm
export const TerraChainNames: ReadonlyArray<ChainName> = ["terra", "terra2"] as const;
export const TerraChainNames: ReadonlyArray<ChainName> = [
"terra",
"terra2",
] as const;
export type TerraChainName = (typeof TerraChainNames)[number];
export type Contracts = {
@ -810,7 +815,7 @@ export function isEVMChain(
chain: ChainId | ChainName
): chain is EVMChainId | EVMChainName {
const chainName = coalesceChainName(chain);
return EVMChainNames.includes(chainName)
return EVMChainNames.includes(chainName);
}
export function isCosmWasmChain(

View File

@ -384,7 +384,7 @@ function serialiseCoreContractUpgrade(payload: CoreContractUpgrade): string {
}
export interface PortalContractUpgrade<
Module extends "NFTBridge" | "TokenBridge"
Module extends "NFTBridge" | "TokenBridge",
> {
module: Module;
type: "ContractUpgrade";
@ -394,7 +394,7 @@ export interface PortalContractUpgrade<
// Parse a portal contract upgrade payload
function portalContractUpgradeParser<
Module extends "NFTBridge" | "TokenBridge"
Module extends "NFTBridge" | "TokenBridge",
>(module: Module): P<PortalContractUpgrade<Module>> {
return new P(
new Parser()
@ -423,7 +423,7 @@ function portalContractUpgradeParser<
}
function serialisePortalContractUpgrade<
Module extends "NFTBridge" | "TokenBridge"
Module extends "NFTBridge" | "TokenBridge",
>(payload: PortalContractUpgrade<Module>): string {
const body = [
encode("bytes32", encodeString(payload.module)),
@ -438,7 +438,7 @@ function serialisePortalContractUpgrade<
// Registrations
export interface PortalRegisterChain<
Module extends "NFTBridge" | "TokenBridge"
Module extends "NFTBridge" | "TokenBridge",
> {
module: Module;
type: "RegisterChain";
@ -479,7 +479,7 @@ function portalRegisterChainParser<Module extends "NFTBridge" | "TokenBridge">(
}
function serialisePortalRegisterChain<
Module extends "NFTBridge" | "TokenBridge"
Module extends "NFTBridge" | "TokenBridge",
>(payload: PortalRegisterChain<Module>): string {
const body = [
encode("bytes32", encodeString(payload.module)),