[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:
Amin Moghaddam 2024-01-11 13:45:40 +01:00 committed by GitHub
parent cee5da93d8
commit 084f2018a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 515 additions and 11 deletions

View File

@ -1 +1,3 @@
lib/ lib/
.cache*
docs

View File

@ -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.

View File

@ -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"
} }
} }

View File

@ -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
) { ) {

View File

@ -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();

View File

@ -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();

View File

@ -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();

View File

@ -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()}`);
} }
} }
} }

View File

@ -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")))
) )
); );
} }

View File

@ -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`);

171
package-lock.json generated
View File

@ -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",