[contract-manager] More utility scripts and docs (#1222)
* Remove mainnet condition in check proposal Testnet contracts can also listen to mainnet governance so this check does not make sense anymore * Simple script for executing vaas * Add script for evm upgrades * Script to list evm contracts with their versions * More docs
This commit is contained in:
parent
cee5da93d8
commit
084f2018a6
|
@ -1 +1,3 @@
|
||||||
lib/
|
lib/
|
||||||
|
.cache*
|
||||||
|
docs
|
||||||
|
|
|
@ -7,3 +7,21 @@ It has the following structure:
|
||||||
- `store` contains all the necessary information for registered chains and deployed contracts
|
- `store` contains all the necessary information for registered chains and deployed contracts
|
||||||
- `scripts` contains utility scripts to interact with the contract manager and accomplish common tasks
|
- `scripts` contains utility scripts to interact with the contract manager and accomplish common tasks
|
||||||
- `src` contains the contract manager code
|
- `src` contains the contract manager code
|
||||||
|
|
||||||
|
# Main Entities
|
||||||
|
|
||||||
|
Contract Manager has base classes which you can use to interact with the following entities:
|
||||||
|
|
||||||
|
- Chain
|
||||||
|
- PythContract
|
||||||
|
- WormholeContract
|
||||||
|
|
||||||
|
Each of these entities has a specialized class for each supported chain (EVM/Cosmos/Aptos/Sui).
|
||||||
|
|
||||||
|
# Docs
|
||||||
|
|
||||||
|
You can generate the docs by running `npx typedoc src/index.ts` from this directory. Open the docs by opening `docs/index.html` in your browser.
|
||||||
|
|
||||||
|
# Scripts
|
||||||
|
|
||||||
|
You can run the scripts by executing `npx ts-node scripts/<script_name>.ts` from this directory.
|
||||||
|
|
|
@ -20,18 +20,19 @@
|
||||||
"url": "git+https://github.com/pyth-network/pyth-crosschain.git"
|
"url": "git+https://github.com/pyth-network/pyth-crosschain.git"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mysten/sui.js": "^0.37.1",
|
|
||||||
"@certusone/wormhole-sdk": "^0.9.8",
|
"@certusone/wormhole-sdk": "^0.9.8",
|
||||||
|
"@injectivelabs/networks": "1.0.68",
|
||||||
|
"@mysten/sui.js": "^0.37.1",
|
||||||
"@pythnetwork/cosmwasm-deploy-tools": "*",
|
"@pythnetwork/cosmwasm-deploy-tools": "*",
|
||||||
"@pythnetwork/price-service-client": "*",
|
"@pythnetwork/price-service-client": "*",
|
||||||
"@pythnetwork/pyth-sui-js": "*",
|
"@pythnetwork/pyth-sui-js": "*",
|
||||||
"@injectivelabs/networks": "1.0.68",
|
|
||||||
"aptos": "^1.5.0",
|
"aptos": "^1.5.0",
|
||||||
"bs58": "^5.0.0",
|
"bs58": "^5.0.0",
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
"typescript": "^4.9.3"
|
"typescript": "^4.9.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"prettier": "^2.6.2"
|
"prettier": "^2.6.2",
|
||||||
|
"typedoc": "^0.25.7"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,6 @@ async function main() {
|
||||||
for (const chain of Object.values(DefaultStore.chains)) {
|
for (const chain of Object.values(DefaultStore.chains)) {
|
||||||
if (
|
if (
|
||||||
chain instanceof EvmChain &&
|
chain instanceof EvmChain &&
|
||||||
chain.isMainnet() === (cluster === "mainnet-beta") &&
|
|
||||||
chain.wormholeChainName ===
|
chain.wormholeChainName ===
|
||||||
instruction.governanceAction.targetChainId
|
instruction.governanceAction.targetChainId
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
import yargs from "yargs";
|
||||||
|
import { hideBin } from "yargs/helpers";
|
||||||
|
import { DefaultStore } from "../src/store";
|
||||||
|
import { SubmittedWormholeMessage, Vault } from "../src/governance";
|
||||||
|
import { parseVaa } from "@certusone/wormhole-sdk";
|
||||||
|
import { decodeGovernancePayload } from "xc_admin_common";
|
||||||
|
import { executeVaa } from "../src/executor";
|
||||||
|
import { toPrivateKey } from "../src";
|
||||||
|
|
||||||
|
const parser = yargs(hideBin(process.argv))
|
||||||
|
.usage(
|
||||||
|
"Tries to execute all vaas on a vault.\n" +
|
||||||
|
"Useful for batch upgrades.\n" +
|
||||||
|
"Usage: $0 --vault <mainnet|devnet> --private-key <private-key> --offset <offset> [--dryrun]"
|
||||||
|
)
|
||||||
|
.options({
|
||||||
|
vault: {
|
||||||
|
type: "string",
|
||||||
|
default: "mainnet",
|
||||||
|
choices: ["mainnet", "devnet"],
|
||||||
|
desc: "Which vault to use for fetching VAAs",
|
||||||
|
},
|
||||||
|
"private-key": {
|
||||||
|
type: "string",
|
||||||
|
demandOption: true,
|
||||||
|
desc: "Private key to sign the transactions executing the governance VAAs. Hex format, without 0x prefix.",
|
||||||
|
},
|
||||||
|
offset: {
|
||||||
|
type: "number",
|
||||||
|
demandOption: true,
|
||||||
|
desc: "Offset to use from the last executed sequence number",
|
||||||
|
},
|
||||||
|
dryrun: {
|
||||||
|
type: "boolean",
|
||||||
|
default: false,
|
||||||
|
desc: "Whether to execute the VAAs or just print them",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const argv = await parser.argv;
|
||||||
|
let vault: Vault;
|
||||||
|
if (argv.vault === "mainnet") {
|
||||||
|
vault =
|
||||||
|
DefaultStore.vaults[
|
||||||
|
"mainnet-beta_FVQyHcooAtThJ83XFrNnv74BcinbRH3bRmfFamAHBfuj"
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
vault =
|
||||||
|
DefaultStore.vaults[
|
||||||
|
"devnet_6baWtW1zTUVMSJHJQVxDUXWzqrQeYBr6mu31j3bTKwY3"
|
||||||
|
];
|
||||||
|
}
|
||||||
|
console.log("Executing VAAs for vault", vault.getId());
|
||||||
|
console.log(
|
||||||
|
"Executing VAAs for emitter",
|
||||||
|
(await vault.getEmitter()).toBase58()
|
||||||
|
);
|
||||||
|
const lastSequenceNumber = await vault.getLastSequenceNumber();
|
||||||
|
const startSequenceNumber = lastSequenceNumber - argv.offset;
|
||||||
|
console.log(
|
||||||
|
`Going from sequence number ${startSequenceNumber} to ${lastSequenceNumber}`
|
||||||
|
);
|
||||||
|
for (
|
||||||
|
let seqNumber = startSequenceNumber;
|
||||||
|
seqNumber <= lastSequenceNumber;
|
||||||
|
seqNumber++
|
||||||
|
) {
|
||||||
|
const submittedWormholeMessage = new SubmittedWormholeMessage(
|
||||||
|
await vault.getEmitter(),
|
||||||
|
seqNumber,
|
||||||
|
vault.cluster
|
||||||
|
);
|
||||||
|
const vaa = await submittedWormholeMessage.fetchVaa();
|
||||||
|
const decodedAction = decodeGovernancePayload(parseVaa(vaa).payload);
|
||||||
|
if (!decodedAction) {
|
||||||
|
console.log("Skipping unknown action for vaa ", seqNumber);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
console.log("Executing vaa", seqNumber);
|
||||||
|
console.log(decodedAction);
|
||||||
|
if (!argv.dryrun) {
|
||||||
|
await executeVaa(toPrivateKey(argv["private-key"]), vaa);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
|
@ -0,0 +1,42 @@
|
||||||
|
import yargs from "yargs";
|
||||||
|
import { hideBin } from "yargs/helpers";
|
||||||
|
import {
|
||||||
|
AptosContract,
|
||||||
|
CosmWasmContract,
|
||||||
|
DefaultStore,
|
||||||
|
EvmContract,
|
||||||
|
} from "../src";
|
||||||
|
|
||||||
|
const parser = yargs(hideBin(process.argv))
|
||||||
|
.usage("Usage: $0")
|
||||||
|
.options({
|
||||||
|
testnet: {
|
||||||
|
type: "boolean",
|
||||||
|
default: false,
|
||||||
|
desc: "Fetch testnet contract fees instead of mainnet",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const argv = await parser.argv;
|
||||||
|
const entries = [];
|
||||||
|
for (const contract of Object.values(DefaultStore.contracts)) {
|
||||||
|
if (contract.getChain().isMainnet() === argv.testnet) continue;
|
||||||
|
if (contract instanceof EvmContract) {
|
||||||
|
try {
|
||||||
|
const version = await contract.getVersion();
|
||||||
|
entries.push({
|
||||||
|
chain: contract.getChain().getId(),
|
||||||
|
contract: contract.address,
|
||||||
|
version: version,
|
||||||
|
});
|
||||||
|
console.log(`Fetched version for ${contract.getId()}`);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(`Error fetching version for ${contract.getId()}`, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.table(entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
|
@ -0,0 +1,127 @@
|
||||||
|
import yargs from "yargs";
|
||||||
|
import { hideBin } from "yargs/helpers";
|
||||||
|
import { DefaultStore, EvmChain, loadHotWallet, toPrivateKey } from "../src";
|
||||||
|
import { existsSync, readFileSync, writeFileSync } from "fs";
|
||||||
|
|
||||||
|
const CACHE_FILE = ".cache-upgrade-evm";
|
||||||
|
|
||||||
|
const parser = yargs(hideBin(process.argv))
|
||||||
|
.usage(
|
||||||
|
"Deploys a new PythUpgradable contract to a set of chains and creates a governance proposal for it.\n" +
|
||||||
|
`Uses a cache file (${CACHE_FILE}) to avoid deploying contracts twice\n` +
|
||||||
|
"Usage: $0 --chain <chain_1> --chain <chain_2> --private-key <private_key> --ops-key-path <ops_key_path> --std-output <std_output>"
|
||||||
|
)
|
||||||
|
.options({
|
||||||
|
testnet: {
|
||||||
|
type: "boolean",
|
||||||
|
default: false,
|
||||||
|
desc: "Upgrade testnet contracts instead of mainnet",
|
||||||
|
},
|
||||||
|
"all-chains": {
|
||||||
|
type: "boolean",
|
||||||
|
default: false,
|
||||||
|
desc: "Upgrade the contract on all chains. Use with --testnet flag to upgrade all testnet contracts",
|
||||||
|
},
|
||||||
|
chain: {
|
||||||
|
type: "array",
|
||||||
|
string: true,
|
||||||
|
desc: "Chains to upgrade the contract on",
|
||||||
|
},
|
||||||
|
"private-key": {
|
||||||
|
type: "string",
|
||||||
|
demandOption: true,
|
||||||
|
desc: "Private key to use for the deployment",
|
||||||
|
},
|
||||||
|
"ops-key-path": {
|
||||||
|
type: "string",
|
||||||
|
demandOption: true,
|
||||||
|
desc: "Path to the private key of the proposer to use for the operations multisig governance proposal",
|
||||||
|
},
|
||||||
|
"std-output": {
|
||||||
|
type: "string",
|
||||||
|
demandOption: true,
|
||||||
|
desc: "Path to the standard JSON output of the pyth contract (build artifact)",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
async function run_if_not_cached(
|
||||||
|
cache_key: string,
|
||||||
|
fn: () => Promise<string>
|
||||||
|
): Promise<string> {
|
||||||
|
const cache = existsSync(CACHE_FILE)
|
||||||
|
? JSON.parse(readFileSync(CACHE_FILE, "utf8"))
|
||||||
|
: {};
|
||||||
|
if (cache[cache_key]) {
|
||||||
|
return cache[cache_key];
|
||||||
|
}
|
||||||
|
const result = await fn();
|
||||||
|
cache[cache_key] = result;
|
||||||
|
writeFileSync(CACHE_FILE, JSON.stringify(cache, null, 2));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const argv = await parser.argv;
|
||||||
|
const selectedChains: EvmChain[] = [];
|
||||||
|
|
||||||
|
if (argv.allChains && argv.chain)
|
||||||
|
throw new Error("Cannot use both --all-chains and --chain");
|
||||||
|
if (!argv.allChains && !argv.chain)
|
||||||
|
throw new Error("Must use either --all-chains or --chain");
|
||||||
|
for (const chain of Object.values(DefaultStore.chains)) {
|
||||||
|
if (!(chain instanceof EvmChain)) continue;
|
||||||
|
if (
|
||||||
|
(argv.allChains && chain.isMainnet() !== argv.testnet) ||
|
||||||
|
argv.chain?.includes(chain.getId())
|
||||||
|
)
|
||||||
|
selectedChains.push(chain);
|
||||||
|
}
|
||||||
|
if (argv.chain && selectedChains.length !== argv.chain.length)
|
||||||
|
throw new Error(
|
||||||
|
`Some chains were not found ${selectedChains
|
||||||
|
.map((chain) => chain.getId())
|
||||||
|
.toString()}`
|
||||||
|
);
|
||||||
|
for (const chain of selectedChains) {
|
||||||
|
if (chain.isMainnet() != selectedChains[0].isMainnet())
|
||||||
|
throw new Error("All chains must be either mainnet or testnet");
|
||||||
|
}
|
||||||
|
|
||||||
|
const vault =
|
||||||
|
DefaultStore.vaults[
|
||||||
|
"mainnet-beta_FVQyHcooAtThJ83XFrNnv74BcinbRH3bRmfFamAHBfuj"
|
||||||
|
];
|
||||||
|
|
||||||
|
console.log("Using cache file", CACHE_FILE);
|
||||||
|
console.log(
|
||||||
|
"Upgrading on chains",
|
||||||
|
selectedChains.map((c) => c.getId())
|
||||||
|
);
|
||||||
|
|
||||||
|
const payloads: Buffer[] = [];
|
||||||
|
for (const chain of selectedChains) {
|
||||||
|
const artifact = JSON.parse(readFileSync(argv["std-output"], "utf8"));
|
||||||
|
console.log("Deploying contract to", chain.getId());
|
||||||
|
const address = await run_if_not_cached(`deploy-${chain.getId()}`, () => {
|
||||||
|
return chain.deploy(
|
||||||
|
toPrivateKey(argv["private-key"]),
|
||||||
|
artifact["abi"],
|
||||||
|
artifact["bytecode"],
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
console.log(`Deployed contract at ${address} on ${chain.getId()}`);
|
||||||
|
payloads.push(
|
||||||
|
chain.generateGovernanceUpgradePayload(address.replace("0x", ""))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Using vault at for proposal", vault.getId());
|
||||||
|
const wallet = await loadHotWallet(argv["ops-key-path"]);
|
||||||
|
console.log("Using wallet ", wallet.publicKey.toBase58());
|
||||||
|
await vault.connect(wallet);
|
||||||
|
const proposal = await vault.proposeWormholeMessage(payloads);
|
||||||
|
console.log("Proposal address", proposal.address.toBase58());
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
|
@ -23,8 +23,16 @@ export async function executeVaa(senderPrivateKey: PrivateKey, vaa: Buffer) {
|
||||||
parsedVaa.emitterAddress.toString("hex") &&
|
parsedVaa.emitterAddress.toString("hex") &&
|
||||||
governanceSource.emitterChain === parsedVaa.emitterChain
|
governanceSource.emitterChain === parsedVaa.emitterChain
|
||||||
) {
|
) {
|
||||||
// TODO: check governance sequence number as well
|
const lastExecutedSequence =
|
||||||
|
await contract.getLastExecutedGovernanceSequence();
|
||||||
|
if (lastExecutedSequence >= parsedVaa.sequence) {
|
||||||
|
console.log(
|
||||||
|
`Skipping on contract ${contract.getId()} as it was already executed`
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
await contract.executeGovernanceInstruction(senderPrivateKey, vaa);
|
await contract.executeGovernanceInstruction(senderPrivateKey, vaa);
|
||||||
|
console.log(`Executed on contract ${contract.getId()}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -200,13 +200,16 @@ export class WormholeEmitter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class WormholeMultiSigTransaction {
|
export class WormholeMultisigProposal {
|
||||||
constructor(
|
constructor(
|
||||||
public address: PublicKey,
|
public address: PublicKey,
|
||||||
public squad: SquadsMesh,
|
public squad: SquadsMesh,
|
||||||
public cluster: PythCluster
|
public cluster: PythCluster
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current state of the proposal which can be "active", "draft", "executed", etc.
|
||||||
|
*/
|
||||||
async getState() {
|
async getState() {
|
||||||
const proposal = await this.squad.getTransaction(this.address);
|
const proposal = await this.squad.getTransaction(this.address);
|
||||||
// Converts the status object to a string e.g
|
// Converts the status object to a string e.g
|
||||||
|
@ -214,6 +217,10 @@ export class WormholeMultiSigTransaction {
|
||||||
return Object.keys(proposal.status)[0];
|
return Object.keys(proposal.status)[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the proposal and returns the wormhole messages that were sent
|
||||||
|
* The proposal must be already approved.
|
||||||
|
*/
|
||||||
async execute(): Promise<SubmittedWormholeMessage[]> {
|
async execute(): Promise<SubmittedWormholeMessage[]> {
|
||||||
const proposal = await this.squad.getTransaction(this.address);
|
const proposal = await this.squad.getTransaction(this.address);
|
||||||
const signatures = await executeProposal(
|
const signatures = await executeProposal(
|
||||||
|
@ -239,6 +246,10 @@ export class WormholeMultiSigTransaction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A vault represents a pyth multisig governance realm which exists in solana mainnet or testnet.
|
||||||
|
* It can be used for proposals to send wormhole messages to the wormhole bridge.
|
||||||
|
*/
|
||||||
export class Vault extends Storable {
|
export class Vault extends Storable {
|
||||||
static type = "vault";
|
static type = "vault";
|
||||||
key: PublicKey;
|
key: PublicKey;
|
||||||
|
@ -276,6 +287,11 @@ export class Vault extends Storable {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connects the vault to a wallet that can be used to submit proposals
|
||||||
|
* The wallet should be a multisig signer of the vault
|
||||||
|
* @param wallet
|
||||||
|
*/
|
||||||
public connect(wallet: Wallet): void {
|
public connect(wallet: Wallet): void {
|
||||||
this.squad = SquadsMesh.endpoint(
|
this.squad = SquadsMesh.endpoint(
|
||||||
getPythClusterApiUrl(this.cluster),
|
getPythClusterApiUrl(this.cluster),
|
||||||
|
@ -288,6 +304,9 @@ export class Vault extends Storable {
|
||||||
return this.squad;
|
return this.squad;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the emitter address of the vault
|
||||||
|
*/
|
||||||
public async getEmitter() {
|
public async getEmitter() {
|
||||||
const squad = SquadsMesh.endpoint(
|
const squad = SquadsMesh.endpoint(
|
||||||
getPythClusterApiUrl(this.cluster),
|
getPythClusterApiUrl(this.cluster),
|
||||||
|
@ -296,10 +315,33 @@ export class Vault extends Storable {
|
||||||
return squad.getAuthorityPDA(this.key, 1);
|
return squad.getAuthorityPDA(this.key, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the last sequence number of the vault emitter
|
||||||
|
* This is used to determine the sequence number of the next wormhole message
|
||||||
|
* Fetches the sequence number from the wormholescan API
|
||||||
|
* @returns the last sequence number
|
||||||
|
*/
|
||||||
|
public async getLastSequenceNumber(): Promise<number> {
|
||||||
|
const rpcUrl = WORMHOLE_API_ENDPOINT[this.cluster];
|
||||||
|
const emitter = await this.getEmitter();
|
||||||
|
const response = await fetch(
|
||||||
|
`${rpcUrl}/api/v1/vaas/1/${emitter.toBase58()}`
|
||||||
|
);
|
||||||
|
const { data } = await response.json();
|
||||||
|
return data[0].sequence;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Proposes sending an array of wormhole messages to the wormhole bridge
|
||||||
|
* Requires a wallet to be connected to the vault
|
||||||
|
*
|
||||||
|
* @param payloads the payloads to send to the wormhole bridge
|
||||||
|
* @param proposalAddress if specified, will continue an existing proposal
|
||||||
|
*/
|
||||||
public async proposeWormholeMessage(
|
public async proposeWormholeMessage(
|
||||||
payloads: Buffer[],
|
payloads: Buffer[],
|
||||||
proposalAddress?: PublicKey
|
proposalAddress?: PublicKey
|
||||||
): Promise<WormholeMultiSigTransaction> {
|
): Promise<WormholeMultisigProposal> {
|
||||||
const squad = this.getSquadOrThrow();
|
const squad = this.getSquadOrThrow();
|
||||||
const multisigVault = new MultisigVault(
|
const multisigVault = new MultisigVault(
|
||||||
squad.wallet,
|
squad.wallet,
|
||||||
|
@ -313,14 +355,19 @@ export class Vault extends Storable {
|
||||||
squad.wallet.publicKey,
|
squad.wallet.publicKey,
|
||||||
proposalAddress
|
proposalAddress
|
||||||
);
|
);
|
||||||
return new WormholeMultiSigTransaction(txAccount, squad, this.cluster);
|
return new WormholeMultisigProposal(txAccount, squad, this.cluster);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function loadHotWallet(wallet: string): Promise<Wallet> {
|
/**
|
||||||
|
* Loads a solana wallet from a file. The file should contain the secret key in array of integers format
|
||||||
|
* This wallet can be used to connect to a vault and submit proposals
|
||||||
|
* @param walletPath path to the wallet file
|
||||||
|
*/
|
||||||
|
export async function loadHotWallet(walletPath: string): Promise<Wallet> {
|
||||||
return new NodeWallet(
|
return new NodeWallet(
|
||||||
Keypair.fromSecretKey(
|
Keypair.fromSecretKey(
|
||||||
Uint8Array.from(JSON.parse(readFileSync(wallet, "ascii")))
|
Uint8Array.from(JSON.parse(readFileSync(walletPath, "ascii")))
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -146,4 +146,7 @@ export class Store {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DefaultStore loads all the contracts and chains from the store directory and provides a single point of access to them.
|
||||||
|
*/
|
||||||
export const DefaultStore = new Store(`${__dirname}/../store`);
|
export const DefaultStore = new Store(`${__dirname}/../store`);
|
||||||
|
|
|
@ -51,7 +51,8 @@
|
||||||
"typescript": "^4.9.3"
|
"typescript": "^4.9.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"prettier": "^2.6.2"
|
"prettier": "^2.6.2",
|
||||||
|
"typedoc": "^0.25.7"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"contract_manager/node_modules/@certusone/wormhole-sdk": {
|
"contract_manager/node_modules/@certusone/wormhole-sdk": {
|
||||||
|
@ -20839,6 +20840,12 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ansi-sequence-parser": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-sequence-parser/-/ansi-sequence-parser-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-vJXt3yiaUL4UU546s3rPXlsry/RnM730G1+HkpKE012AN0sx1eOrxSu95oKDIonskeLTijMgqWZ3uDEe3NFvyg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/ansi-styles": {
|
"node_modules/ansi-styles": {
|
||||||
"version": "4.3.0",
|
"version": "4.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||||
|
@ -36503,6 +36510,12 @@
|
||||||
"resolved": "https://registry.npmjs.org/ltgt/-/ltgt-2.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/ltgt/-/ltgt-2.2.1.tgz",
|
||||||
"integrity": "sha512-AI2r85+4MquTw9ZYqabu4nMwy9Oftlfa/e/52t9IjtfG+mGBbTNdAoZ3RQKLHR6r0wQnwZnPIEh/Ya6XTWAKNA=="
|
"integrity": "sha512-AI2r85+4MquTw9ZYqabu4nMwy9Oftlfa/e/52t9IjtfG+mGBbTNdAoZ3RQKLHR6r0wQnwZnPIEh/Ya6XTWAKNA=="
|
||||||
},
|
},
|
||||||
|
"node_modules/lunr": {
|
||||||
|
"version": "2.3.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz",
|
||||||
|
"integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/lz-string": {
|
"node_modules/lz-string": {
|
||||||
"version": "1.5.0",
|
"version": "1.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz",
|
||||||
|
@ -36605,6 +36618,18 @@
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/marked": {
|
||||||
|
"version": "4.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz",
|
||||||
|
"integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==",
|
||||||
|
"dev": true,
|
||||||
|
"bin": {
|
||||||
|
"marked": "bin/marked.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/mcl-wasm": {
|
"node_modules/mcl-wasm": {
|
||||||
"version": "0.7.9",
|
"version": "0.7.9",
|
||||||
"resolved": "https://registry.npmjs.org/mcl-wasm/-/mcl-wasm-0.7.9.tgz",
|
"resolved": "https://registry.npmjs.org/mcl-wasm/-/mcl-wasm-0.7.9.tgz",
|
||||||
|
@ -47697,6 +47722,18 @@
|
||||||
"url": "https://github.com/sponsors/isaacs"
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/shiki": {
|
||||||
|
"version": "0.14.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.7.tgz",
|
||||||
|
"integrity": "sha512-dNPAPrxSc87ua2sKJ3H5dQ/6ZaY8RNnaAqK+t0eG7p0Soi2ydiqbGOTaZCqaYvA/uZYfS1LJnemt3Q+mSfcPCg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-sequence-parser": "^1.1.0",
|
||||||
|
"jsonc-parser": "^3.2.0",
|
||||||
|
"vscode-oniguruma": "^1.7.0",
|
||||||
|
"vscode-textmate": "^8.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/shx": {
|
"node_modules/shx": {
|
||||||
"version": "0.3.4",
|
"version": "0.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/shx/-/shx-0.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/shx/-/shx-0.3.4.tgz",
|
||||||
|
@ -51734,6 +51771,51 @@
|
||||||
"is-typedarray": "^1.0.0"
|
"is-typedarray": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/typedoc": {
|
||||||
|
"version": "0.25.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.25.7.tgz",
|
||||||
|
"integrity": "sha512-m6A6JjQRg39p2ZVRIN3NKXgrN8vzlHhOS+r9ymUYtcUP/TIQPvWSq7YgE5ZjASfv5Vd5BW5xrir6Gm2XNNcOow==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"lunr": "^2.3.9",
|
||||||
|
"marked": "^4.3.0",
|
||||||
|
"minimatch": "^9.0.3",
|
||||||
|
"shiki": "^0.14.7"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"typedoc": "bin/typedoc"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 16"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x || 5.3.x"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/typedoc/node_modules/brace-expansion": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"balanced-match": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/typedoc/node_modules/minimatch": {
|
||||||
|
"version": "9.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
|
||||||
|
"integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"brace-expansion": "^2.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16 || 14 >=14.17"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/typeforce": {
|
"node_modules/typeforce": {
|
||||||
"version": "1.18.0",
|
"version": "1.18.0",
|
||||||
"resolved": "https://registry.npmjs.org/typeforce/-/typeforce-1.18.0.tgz",
|
"resolved": "https://registry.npmjs.org/typeforce/-/typeforce-1.18.0.tgz",
|
||||||
|
@ -52372,6 +52454,18 @@
|
||||||
"resolved": "https://registry.npmjs.org/vlq/-/vlq-2.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/vlq/-/vlq-2.0.4.tgz",
|
||||||
"integrity": "sha512-aodjPa2wPQFkra1G8CzJBTHXhgk3EVSwxSWXNPr1fgdFLUb8kvLV1iEb6rFgasIsjP82HWI6dsb5Io26DDnasA=="
|
"integrity": "sha512-aodjPa2wPQFkra1G8CzJBTHXhgk3EVSwxSWXNPr1fgdFLUb8kvLV1iEb6rFgasIsjP82HWI6dsb5Io26DDnasA=="
|
||||||
},
|
},
|
||||||
|
"node_modules/vscode-oniguruma": {
|
||||||
|
"version": "1.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz",
|
||||||
|
"integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/vscode-textmate": {
|
||||||
|
"version": "8.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz",
|
||||||
|
"integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/vuvuzela": {
|
"node_modules/vuvuzela": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/vuvuzela/-/vuvuzela-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/vuvuzela/-/vuvuzela-1.0.3.tgz",
|
||||||
|
@ -76899,6 +76993,12 @@
|
||||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
|
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
|
||||||
},
|
},
|
||||||
|
"ansi-sequence-parser": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-sequence-parser/-/ansi-sequence-parser-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-vJXt3yiaUL4UU546s3rPXlsry/RnM730G1+HkpKE012AN0sx1eOrxSu95oKDIonskeLTijMgqWZ3uDEe3NFvyg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"ansi-styles": {
|
"ansi-styles": {
|
||||||
"version": "4.3.0",
|
"version": "4.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||||
|
@ -79635,6 +79735,7 @@
|
||||||
"bs58": "^5.0.0",
|
"bs58": "^5.0.0",
|
||||||
"prettier": "^2.6.2",
|
"prettier": "^2.6.2",
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
|
"typedoc": "^0.25.7",
|
||||||
"typescript": "^4.9.3"
|
"typescript": "^4.9.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -89790,6 +89891,12 @@
|
||||||
"resolved": "https://registry.npmjs.org/ltgt/-/ltgt-2.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/ltgt/-/ltgt-2.2.1.tgz",
|
||||||
"integrity": "sha512-AI2r85+4MquTw9ZYqabu4nMwy9Oftlfa/e/52t9IjtfG+mGBbTNdAoZ3RQKLHR6r0wQnwZnPIEh/Ya6XTWAKNA=="
|
"integrity": "sha512-AI2r85+4MquTw9ZYqabu4nMwy9Oftlfa/e/52t9IjtfG+mGBbTNdAoZ3RQKLHR6r0wQnwZnPIEh/Ya6XTWAKNA=="
|
||||||
},
|
},
|
||||||
|
"lunr": {
|
||||||
|
"version": "2.3.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz",
|
||||||
|
"integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"lz-string": {
|
"lz-string": {
|
||||||
"version": "1.5.0",
|
"version": "1.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz",
|
||||||
|
@ -89867,6 +89974,12 @@
|
||||||
"object-visit": "^1.0.0"
|
"object-visit": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"marked": {
|
||||||
|
"version": "4.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz",
|
||||||
|
"integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"mcl-wasm": {
|
"mcl-wasm": {
|
||||||
"version": "0.7.9",
|
"version": "0.7.9",
|
||||||
"resolved": "https://registry.npmjs.org/mcl-wasm/-/mcl-wasm-0.7.9.tgz",
|
"resolved": "https://registry.npmjs.org/mcl-wasm/-/mcl-wasm-0.7.9.tgz",
|
||||||
|
@ -98959,6 +99072,18 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"shiki": {
|
||||||
|
"version": "0.14.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.7.tgz",
|
||||||
|
"integrity": "sha512-dNPAPrxSc87ua2sKJ3H5dQ/6ZaY8RNnaAqK+t0eG7p0Soi2ydiqbGOTaZCqaYvA/uZYfS1LJnemt3Q+mSfcPCg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"ansi-sequence-parser": "^1.1.0",
|
||||||
|
"jsonc-parser": "^3.2.0",
|
||||||
|
"vscode-oniguruma": "^1.7.0",
|
||||||
|
"vscode-textmate": "^8.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"shx": {
|
"shx": {
|
||||||
"version": "0.3.4",
|
"version": "0.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/shx/-/shx-0.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/shx/-/shx-0.3.4.tgz",
|
||||||
|
@ -102108,6 +102233,38 @@
|
||||||
"is-typedarray": "^1.0.0"
|
"is-typedarray": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"typedoc": {
|
||||||
|
"version": "0.25.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.25.7.tgz",
|
||||||
|
"integrity": "sha512-m6A6JjQRg39p2ZVRIN3NKXgrN8vzlHhOS+r9ymUYtcUP/TIQPvWSq7YgE5ZjASfv5Vd5BW5xrir6Gm2XNNcOow==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"lunr": "^2.3.9",
|
||||||
|
"marked": "^4.3.0",
|
||||||
|
"minimatch": "^9.0.3",
|
||||||
|
"shiki": "^0.14.7"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"brace-expansion": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"balanced-match": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"minimatch": {
|
||||||
|
"version": "9.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
|
||||||
|
"integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"brace-expansion": "^2.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"typeforce": {
|
"typeforce": {
|
||||||
"version": "1.18.0",
|
"version": "1.18.0",
|
||||||
"resolved": "https://registry.npmjs.org/typeforce/-/typeforce-1.18.0.tgz",
|
"resolved": "https://registry.npmjs.org/typeforce/-/typeforce-1.18.0.tgz",
|
||||||
|
@ -102613,6 +102770,18 @@
|
||||||
"resolved": "https://registry.npmjs.org/vlq/-/vlq-2.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/vlq/-/vlq-2.0.4.tgz",
|
||||||
"integrity": "sha512-aodjPa2wPQFkra1G8CzJBTHXhgk3EVSwxSWXNPr1fgdFLUb8kvLV1iEb6rFgasIsjP82HWI6dsb5Io26DDnasA=="
|
"integrity": "sha512-aodjPa2wPQFkra1G8CzJBTHXhgk3EVSwxSWXNPr1fgdFLUb8kvLV1iEb6rFgasIsjP82HWI6dsb5Io26DDnasA=="
|
||||||
},
|
},
|
||||||
|
"vscode-oniguruma": {
|
||||||
|
"version": "1.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz",
|
||||||
|
"integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"vscode-textmate": {
|
||||||
|
"version": "8.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz",
|
||||||
|
"integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"vuvuzela": {
|
"vuvuzela": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/vuvuzela/-/vuvuzela-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/vuvuzela/-/vuvuzela-1.0.3.tgz",
|
||||||
|
|
Loading…
Reference in New Issue