├── clients ├── js │ ├── .gitignore │ ├── src │ │ ├── index.ts │ │ ├── plugin.ts │ │ └── generated │ │ │ ├── instructions │ │ │ ├── index.ts │ │ │ └── create.ts │ │ │ ├── errors │ │ │ ├── index.ts │ │ │ └── mplProjectName.ts │ │ │ ├── programs │ │ │ ├── index.ts │ │ │ └── mplProjectName.ts │ │ │ ├── types │ │ │ ├── index.ts │ │ │ ├── key.ts │ │ │ └── myData.ts │ │ │ ├── accounts │ │ │ ├── index.ts │ │ │ ├── myAccount.ts │ │ │ └── myPdaAccount.ts │ │ │ ├── index.ts │ │ │ └── shared │ │ │ └── index.ts │ ├── typedoc.json │ ├── .prettierrc.json │ ├── test │ │ ├── _setup.ts │ │ ├── getProgram.test.ts │ │ └── create.test.ts │ ├── bench │ │ ├── _setup.ts │ │ └── create.ts │ ├── .eslintrc.js │ ├── tsconfig.json │ ├── README.md │ ├── package.json │ └── CONTRIBUTING.md └── rust │ ├── src │ ├── lib.rs │ └── generated │ │ ├── instructions │ │ ├── mod.rs │ │ └── create.rs │ │ ├── errors │ │ ├── mod.rs │ │ └── mpl_project_name.rs │ │ ├── types │ │ ├── mod.rs │ │ ├── my_data.rs │ │ └── key.rs │ │ ├── mod.rs │ │ ├── accounts │ │ ├── mod.rs │ │ ├── my_account.rs │ │ └── my_pda_account.rs │ │ └── programs.rs │ ├── Cargo.toml │ ├── README.md │ ├── CONTRIBUTING.md │ └── tests │ └── create.rs ├── Cargo.toml ├── .gitignore ├── .github ├── .env ├── workflows │ ├── test-rust-client.yml │ ├── test-programs.yml │ ├── build-programs.yml │ ├── test-js-client.yml │ ├── build-rust-client.yml │ ├── benchmark.yml │ ├── publish-rust-client.yml │ ├── publish-js-client.yml │ └── main.yml └── file-filters.yml ├── programs └── mpl-project-name │ ├── rustfmt.toml │ ├── src │ ├── lib.rs │ ├── entrypoint.rs │ ├── instruction.rs │ ├── error.rs │ ├── state.rs │ └── processor.rs │ ├── Cargo.toml │ └── README.md ├── configs ├── scripts │ ├── client │ │ ├── test-js.sh │ │ └── test-rust.sh │ └── program │ │ ├── clean.sh │ │ ├── build.sh │ │ ├── test.sh │ │ └── dump.sh ├── shank.cjs ├── validator.cjs └── kinobi.cjs ├── PROJECT_README.md ├── package.json ├── README.md ├── CONTRIBUTING.md ├── init.sh ├── idls └── mpl_project_name_program.json ├── LICENSE └── pnpm-lock.yaml /clients/js/.gitignore: -------------------------------------------------------------------------------- 1 | .vercel 2 | docs 3 | -------------------------------------------------------------------------------- /clients/js/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './generated'; 2 | export * from './plugin'; 3 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | members = [ 4 | "clients/rust", 5 | "programs/mpl-project-name" 6 | ] 7 | -------------------------------------------------------------------------------- /clients/rust/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod generated; 2 | 3 | pub use generated::programs::MPL_PROJECT_NAME_ID as ID; 4 | pub use generated::*; 5 | -------------------------------------------------------------------------------- /clients/js/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "entryPoints": ["src/index.ts"], 3 | "includeVersion": true, 4 | "readme": "none", 5 | "out": "docs" 6 | } 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .anchor 2 | .DS_Store 3 | **/.DS_Store 4 | **/target 5 | **/*.rs.bk 6 | node_modules 7 | test-ledger 8 | dist 9 | .amman 10 | .crates 11 | .bin 12 | clients/js/output.json -------------------------------------------------------------------------------- /.github/.env: -------------------------------------------------------------------------------- 1 | CARGO_TERM_COLOR=always 2 | NODE_VERSION=16.x 3 | PROGRAMS=["mpl-project-name"] 4 | RUST_VERSION=1.70.0 5 | SOLANA_VERSION=1.16.18 6 | COMMIT_USER_NAME=github-actions 7 | COMMIT_USER_EMAIL=github-actions@github.com 8 | -------------------------------------------------------------------------------- /clients/js/.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "singleQuote": true, 4 | "trailingComma": "es5", 5 | "useTabs": false, 6 | "tabWidth": 2, 7 | "arrowParens": "always", 8 | "printWidth": 80, 9 | "parser": "typescript" 10 | } 11 | -------------------------------------------------------------------------------- /programs/mpl-project-name/rustfmt.toml: -------------------------------------------------------------------------------- 1 | max_width = 100 2 | imports_indent = "Block" 3 | imports_layout = "Mixed" 4 | imports_granularity = "Crate" 5 | group_imports = "Preserve" 6 | reorder_imports = true 7 | reorder_modules = true 8 | reorder_impl_items = false 9 | -------------------------------------------------------------------------------- /programs/mpl-project-name/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod entrypoint; 2 | pub mod error; 3 | pub mod instruction; 4 | pub mod processor; 5 | pub mod state; 6 | 7 | pub use solana_program; 8 | 9 | solana_program::declare_id!("MyProgram1111111111111111111111111111111111"); 10 | -------------------------------------------------------------------------------- /clients/js/src/plugin.ts: -------------------------------------------------------------------------------- 1 | import { UmiPlugin } from '@metaplex-foundation/umi'; 2 | import { createMplProjectNameProgram } from './generated'; 3 | 4 | export const mplProjectName = (): UmiPlugin => ({ 5 | install(umi) { 6 | umi.programs.add(createMplProjectNameProgram(), false); 7 | }, 8 | }); 9 | -------------------------------------------------------------------------------- /clients/js/test/_setup.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-extraneous-dependencies */ 2 | import { createUmi as basecreateUmi } from '@metaplex-foundation/umi-bundle-tests'; 3 | import { mplProjectName } from '../src'; 4 | 5 | export const createUmi = async () => 6 | (await basecreateUmi()).use(mplProjectName()); 7 | -------------------------------------------------------------------------------- /clients/js/bench/_setup.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-extraneous-dependencies */ 2 | import { createUmi as basecreateUmi } from '@metaplex-foundation/umi-bundle-tests'; 3 | import { 4 | mplProjectName, 5 | } from '../src'; 6 | 7 | export const createUmi = async () => (await basecreateUmi()).use(mplProjectName()); 8 | -------------------------------------------------------------------------------- /clients/js/src/generated/instructions/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This code was AUTOGENERATED using the kinobi library. 3 | * Please DO NOT EDIT THIS FILE, instead use visitors 4 | * to add features, then rerun kinobi to update it. 5 | * 6 | * @see https://github.com/metaplex-foundation/kinobi 7 | */ 8 | 9 | export * from './create'; 10 | -------------------------------------------------------------------------------- /clients/js/src/generated/errors/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This code was AUTOGENERATED using the kinobi library. 3 | * Please DO NOT EDIT THIS FILE, instead use visitors 4 | * to add features, then rerun kinobi to update it. 5 | * 6 | * @see https://github.com/metaplex-foundation/kinobi 7 | */ 8 | 9 | export * from './mplProjectName'; 10 | -------------------------------------------------------------------------------- /clients/js/src/generated/programs/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This code was AUTOGENERATED using the kinobi library. 3 | * Please DO NOT EDIT THIS FILE, instead use visitors 4 | * to add features, then rerun kinobi to update it. 5 | * 6 | * @see https://github.com/metaplex-foundation/kinobi 7 | */ 8 | 9 | export * from './mplProjectName'; 10 | -------------------------------------------------------------------------------- /clients/js/src/generated/types/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This code was AUTOGENERATED using the kinobi library. 3 | * Please DO NOT EDIT THIS FILE, instead use visitors 4 | * to add features, then rerun kinobi to update it. 5 | * 6 | * @see https://github.com/metaplex-foundation/kinobi 7 | */ 8 | 9 | export * from './key'; 10 | export * from './myData'; 11 | -------------------------------------------------------------------------------- /clients/rust/src/generated/instructions/mod.rs: -------------------------------------------------------------------------------- 1 | //! This code was AUTOGENERATED using the kinobi library. 2 | //! Please DO NOT EDIT THIS FILE, instead use visitors 3 | //! to add features, then rerun kinobi to update it. 4 | //! 5 | //! [https://github.com/metaplex-foundation/kinobi] 6 | //! 7 | 8 | pub(crate) mod r#create; 9 | 10 | pub use self::r#create::*; 11 | -------------------------------------------------------------------------------- /clients/js/src/generated/accounts/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This code was AUTOGENERATED using the kinobi library. 3 | * Please DO NOT EDIT THIS FILE, instead use visitors 4 | * to add features, then rerun kinobi to update it. 5 | * 6 | * @see https://github.com/metaplex-foundation/kinobi 7 | */ 8 | 9 | export * from './myAccount'; 10 | export * from './myPdaAccount'; 11 | -------------------------------------------------------------------------------- /clients/rust/src/generated/errors/mod.rs: -------------------------------------------------------------------------------- 1 | //! This code was AUTOGENERATED using the kinobi library. 2 | //! Please DO NOT EDIT THIS FILE, instead use visitors 3 | //! to add features, then rerun kinobi to update it. 4 | //! 5 | //! [https://github.com/metaplex-foundation/kinobi] 6 | //! 7 | 8 | pub(crate) mod mpl_project_name; 9 | 10 | pub use self::mpl_project_name::MplProjectNameError; 11 | -------------------------------------------------------------------------------- /configs/scripts/client/test-js.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) 4 | # go to parent folder 5 | cd $(dirname $(dirname $(dirname $SCRIPT_DIR))) 6 | WORKING_DIR=$(pwd) 7 | 8 | # command-line input 9 | ARGS=$* 10 | 11 | # js client tests folder 12 | cd ${WORKING_DIR}/clients/js 13 | 14 | pnpm install && pnpm build && pnpm test ${ARGS} -------------------------------------------------------------------------------- /clients/rust/src/generated/types/mod.rs: -------------------------------------------------------------------------------- 1 | //! This code was AUTOGENERATED using the kinobi library. 2 | //! Please DO NOT EDIT THIS FILE, instead use visitors 3 | //! to add features, then rerun kinobi to update it. 4 | //! 5 | //! [https://github.com/metaplex-foundation/kinobi] 6 | //! 7 | 8 | pub(crate) mod r#key; 9 | pub(crate) mod r#my_data; 10 | 11 | pub use self::r#key::*; 12 | pub use self::r#my_data::*; 13 | -------------------------------------------------------------------------------- /programs/mpl-project-name/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mpl-project-name-program" 3 | version = "0.1.0" 4 | edition = "2021" 5 | readme = "./README.md" 6 | license-file = "../../LICENSE" 7 | publish = false 8 | 9 | [lib] 10 | crate-type = ["cdylib", "lib"] 11 | 12 | [dependencies] 13 | borsh = "^0.10" 14 | shank = "0.3.0" 15 | num-derive = "^0.3" 16 | num-traits = "^0.2" 17 | solana-program = "~1.16" 18 | thiserror = "^1.0" 19 | -------------------------------------------------------------------------------- /clients/rust/src/generated/mod.rs: -------------------------------------------------------------------------------- 1 | //! This code was AUTOGENERATED using the kinobi library. 2 | //! Please DO NOT EDIT THIS FILE, instead use visitors 3 | //! to add features, then rerun kinobi to update it. 4 | //! 5 | //! [https://github.com/metaplex-foundation/kinobi] 6 | //! 7 | 8 | pub mod accounts; 9 | pub mod errors; 10 | pub mod instructions; 11 | pub mod programs; 12 | pub mod types; 13 | 14 | pub(crate) use programs::*; 15 | -------------------------------------------------------------------------------- /clients/rust/src/generated/accounts/mod.rs: -------------------------------------------------------------------------------- 1 | //! This code was AUTOGENERATED using the kinobi library. 2 | //! Please DO NOT EDIT THIS FILE, instead use visitors 3 | //! to add features, then rerun kinobi to update it. 4 | //! 5 | //! [https://github.com/metaplex-foundation/kinobi] 6 | //! 7 | 8 | pub(crate) mod r#my_account; 9 | pub(crate) mod r#my_pda_account; 10 | 11 | pub use self::r#my_account::*; 12 | pub use self::r#my_pda_account::*; 13 | -------------------------------------------------------------------------------- /clients/js/src/generated/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This code was AUTOGENERATED using the kinobi library. 3 | * Please DO NOT EDIT THIS FILE, instead use visitors 4 | * to add features, then rerun kinobi to update it. 5 | * 6 | * @see https://github.com/metaplex-foundation/kinobi 7 | */ 8 | 9 | export * from './accounts'; 10 | export * from './errors'; 11 | export * from './instructions'; 12 | export * from './programs'; 13 | export * from './shared'; 14 | export * from './types'; 15 | -------------------------------------------------------------------------------- /clients/rust/src/generated/programs.rs: -------------------------------------------------------------------------------- 1 | //! This code was AUTOGENERATED using the kinobi library. 2 | //! Please DO NOT EDIT THIS FILE, instead use visitors 3 | //! to add features, then rerun kinobi to update it. 4 | //! 5 | //! [https://github.com/metaplex-foundation/kinobi] 6 | //! 7 | 8 | use solana_program::{pubkey, pubkey::Pubkey}; 9 | 10 | /// `mpl_project_name` program ID. 11 | pub const MPL_PROJECT_NAME_ID: Pubkey = pubkey!("MyProgram1111111111111111111111111111111111"); 12 | -------------------------------------------------------------------------------- /programs/mpl-project-name/README.md: -------------------------------------------------------------------------------- 1 | # Mpl Project Name 2 | 3 | My project description 4 | 5 | ## Building 6 | 7 | This will build the program and output a `.so` file in a non-comitted `target/deploy` directory which is used by the `config/shank.cjs` configuration file to start a new local validator with the latest changes on the program. 8 | 9 | ```sh 10 | cargo build-bpf 11 | ``` 12 | 13 | ## Testing 14 | 15 | You may run the following command to build the program and run its Rust tests. 16 | 17 | ```sh 18 | cargo test-bpf 19 | ``` 20 | -------------------------------------------------------------------------------- /clients/js/test/getProgram.test.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { MPL_PROJECT_NAME_PROGRAM_ID } from '../src'; 3 | import { createUmi } from './_setup'; 4 | 5 | test('it registers the program', async (t) => { 6 | // Given a Umi instance using the project's plugin. 7 | const umi = await createUmi(); 8 | 9 | // When we fetch the registered program. 10 | const program = umi.programs.get('mplProjectName'); 11 | 12 | // Then we expect it to be the same as the program ID constant. 13 | t.true(program.publicKey === MPL_PROJECT_NAME_PROGRAM_ID); 14 | }); 15 | -------------------------------------------------------------------------------- /configs/shank.cjs: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const { generateIdl } = require("@metaplex-foundation/shank-js"); 3 | 4 | const idlDir = path.join(__dirname, "..", "idls"); 5 | const binaryInstallDir = path.join(__dirname, "..", ".crates"); 6 | const programDir = path.join(__dirname, "..", "programs"); 7 | 8 | generateIdl({ 9 | generator: "shank", 10 | programName: "mpl_project_name_program", 11 | programId: "MyProgram1111111111111111111111111111111111", 12 | idlDir, 13 | binaryInstallDir, 14 | programDir: path.join(programDir, "mpl-project-name"), 15 | }); 16 | -------------------------------------------------------------------------------- /configs/scripts/program/clean.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) 4 | OUTPUT="./programs/.bin" 5 | # go to parent folder 6 | cd $(dirname $(dirname $(dirname ${SCRIPT_DIR}))) 7 | 8 | rm -rf $OUTPUT 9 | 10 | if [ -z ${PROGRAMS+x} ]; then 11 | PROGRAMS="$(cat .github/.env | grep "PROGRAMS" | cut -d '=' -f 2)" 12 | fi 13 | 14 | PROGRAMS=$(echo ${PROGRAMS} | jq -c '.[]' | sed 's/"//g') 15 | WORKING_DIR=$(pwd) 16 | 17 | for p in ${PROGRAMS[@]}; do 18 | cd ${WORKING_DIR}/programs/${p} 19 | rm -rf target 20 | done -------------------------------------------------------------------------------- /clients/rust/src/generated/types/my_data.rs: -------------------------------------------------------------------------------- 1 | //! This code was AUTOGENERATED using the kinobi library. 2 | //! Please DO NOT EDIT THIS FILE, instead use visitors 3 | //! to add features, then rerun kinobi to update it. 4 | //! 5 | //! [https://github.com/metaplex-foundation/kinobi] 6 | //! 7 | 8 | use borsh::BorshDeserialize; 9 | use borsh::BorshSerialize; 10 | 11 | #[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] 12 | #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 13 | pub struct MyData { 14 | pub field1: u16, 15 | pub field2: u32, 16 | } 17 | -------------------------------------------------------------------------------- /PROJECT_README.md: -------------------------------------------------------------------------------- 1 | # Mpl Project Name 2 | 3 | My project description 4 | 5 | ## Programs 6 | 7 | This project contains the following programs: 8 | 9 | - [Mpl Project Name](./programs/mpl-project-name/README.md) `MyProgram1111111111111111111111111111111111` 10 | 11 | You will need a Rust version compatible with BPF to compile the program, currently we recommend using Rust 1.68.0. 12 | 13 | ## Clients 14 | 15 | This project contains the following clients: 16 | 17 | - [JavaScript](./clients/js/README.md) 18 | - [Rust](./clients/rust/README.md) 19 | 20 | ## Contributing 21 | 22 | Check out the [Contributing Guide](./CONTRIBUTING.md) the learn more about how to contribute to this project. 23 | -------------------------------------------------------------------------------- /clients/rust/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mpl-project-name" 3 | version = "0.1.0" 4 | edition = "2021" 5 | readme = "README.md" 6 | license-file = "../../LICENSE" 7 | 8 | [lib] 9 | crate-type = ["cdylib", "lib"] 10 | 11 | [features] 12 | test-sbf = [] 13 | serde = ["dep:serde", "dep:serde_with"] 14 | 15 | [dependencies] 16 | borsh = "^0.10" 17 | num-derive = "^0.3" 18 | num-traits = "^0.2" 19 | serde = { version = "^1.0", features = ["derive"], optional = true } 20 | serde_with = { version = "^3.0", optional = true } 21 | solana-program = "~1.16" 22 | thiserror = "^1.0" 23 | 24 | [dev-dependencies] 25 | assert_matches = "1.5.0" 26 | solana-program-test = "~1.16" 27 | solana-sdk = "~1.16" 28 | -------------------------------------------------------------------------------- /clients/rust/src/generated/types/key.rs: -------------------------------------------------------------------------------- 1 | //! This code was AUTOGENERATED using the kinobi library. 2 | //! Please DO NOT EDIT THIS FILE, instead use visitors 3 | //! to add features, then rerun kinobi to update it. 4 | //! 5 | //! [https://github.com/metaplex-foundation/kinobi] 6 | //! 7 | 8 | use borsh::BorshDeserialize; 9 | use borsh::BorshSerialize; 10 | use num_derive::FromPrimitive; 11 | 12 | #[derive( 13 | BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq, PartialOrd, Hash, FromPrimitive, 14 | )] 15 | #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 16 | pub enum Key { 17 | Uninitialized, 18 | MyAccount, 19 | MyPdaAccount, 20 | } 21 | -------------------------------------------------------------------------------- /clients/js/src/generated/types/key.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This code was AUTOGENERATED using the kinobi library. 3 | * Please DO NOT EDIT THIS FILE, instead use visitors 4 | * to add features, then rerun kinobi to update it. 5 | * 6 | * @see https://github.com/metaplex-foundation/kinobi 7 | */ 8 | 9 | import { Serializer, scalarEnum } from '@metaplex-foundation/umi/serializers'; 10 | 11 | export enum Key { 12 | Uninitialized, 13 | MyAccount, 14 | MyPdaAccount, 15 | } 16 | 17 | export type KeyArgs = Key; 18 | 19 | export function getKeySerializer(): Serializer { 20 | return scalarEnum(Key, { description: 'Key' }) as Serializer< 21 | KeyArgs, 22 | Key 23 | >; 24 | } 25 | -------------------------------------------------------------------------------- /configs/scripts/client/test-rust.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) 4 | PROGRAMS_OUTPUT="./programs/.bin" 5 | # go to parent folder 6 | cd $(dirname $(dirname $(dirname $SCRIPT_DIR))) 7 | 8 | # command-line input 9 | ARGS=$* 10 | 11 | WORKING_DIR=$(pwd) 12 | SOLFMT="solfmt" 13 | export SBF_OUT_DIR="${WORKING_DIR}/${PROGRAMS_OUTPUT}" 14 | 15 | # client SDK tests 16 | cd ${WORKING_DIR}/clients/rust 17 | 18 | if [ ! "$(command -v $SOLFMT)" = "" ]; then 19 | CARGO_TERM_COLOR=always cargo test-sbf --sbf-out-dir ${WORKING_DIR}/${PROGRAMS_OUTPUT} ${ARGS} 2>&1 | ${SOLFMT} 20 | else 21 | cargo test-sbf --sbf-out-dir ${WORKING_DIR}/${PROGRAMS_OUTPUT} ${ARGS} 22 | fi -------------------------------------------------------------------------------- /programs/mpl-project-name/src/entrypoint.rs: -------------------------------------------------------------------------------- 1 | use solana_program::{ 2 | account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, 3 | program_error::PrintProgramError, pubkey::Pubkey, 4 | }; 5 | 6 | use crate::{error::MplProjectNameError, processor}; 7 | 8 | entrypoint!(process_instruction); 9 | fn process_instruction<'a>( 10 | program_id: &'a Pubkey, 11 | accounts: &'a [AccountInfo<'a>], 12 | instruction_data: &[u8], 13 | ) -> ProgramResult { 14 | if let Err(error) = processor::process_instruction(program_id, accounts, instruction_data) { 15 | // catch the error so we can print it 16 | error.print::(); 17 | return Err(error); 18 | } 19 | Ok(()) 20 | } 21 | -------------------------------------------------------------------------------- /clients/rust/README.md: -------------------------------------------------------------------------------- 1 | # Rust client SDK for Mpl Project Name 2 | 3 | An autogenerated Rust client SDK for the project. 4 | 5 | ## Getting started 6 | 7 | From your project folder: 8 | 9 | ```bash 10 | cargo add mpl-project-name 11 | ``` 12 | 13 | ## Structure 14 | 15 | The client SDK is divided into several modules: 16 | 17 | - `accounts`: structs representing the accounts of the program 18 | - `errors`: enums representing the program errors 19 | - `instructions`: structs to facilitate the creation of instructions, instruction arguments and CPI instructions 20 | - `types`: structs representing types used by the program 21 | 22 | ## Contributing 23 | 24 | Check out the [Contributing Guide](./CONTRIBUTING.md) the learn more about how to contribute to this library. 25 | -------------------------------------------------------------------------------- /clients/js/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['airbnb-base', 'airbnb-typescript/base', 'prettier'], 3 | plugins: ['prettier'], 4 | overrides: [], 5 | parserOptions: { 6 | ecmaVersion: 'latest', 7 | sourceType: 'module', 8 | project: 'tsconfig.json', 9 | tsconfigRootDir: __dirname, 10 | }, 11 | rules: { 12 | '@typescript-eslint/no-use-before-define': 'off', 13 | '@typescript-eslint/no-unused-vars': 'off', 14 | 'class-methods-use-this': 'off', 15 | 'import/prefer-default-export': 'off', 16 | 'import/no-cycle': 'off', 17 | 'no-underscore-dangle': 'off', 18 | 'max-classes-per-file': 'off', 19 | 'no-param-reassign': 'off', 20 | 'func-names': 'off', 21 | }, 22 | ignorePatterns: ['dist/**', '.eslintrc.js'], 23 | }; 24 | -------------------------------------------------------------------------------- /clients/js/src/generated/types/myData.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This code was AUTOGENERATED using the kinobi library. 3 | * Please DO NOT EDIT THIS FILE, instead use visitors 4 | * to add features, then rerun kinobi to update it. 5 | * 6 | * @see https://github.com/metaplex-foundation/kinobi 7 | */ 8 | 9 | import { 10 | Serializer, 11 | struct, 12 | u16, 13 | u32, 14 | } from '@metaplex-foundation/umi/serializers'; 15 | 16 | export type MyData = { field1: number; field2: number }; 17 | 18 | export type MyDataArgs = MyData; 19 | 20 | export function getMyDataSerializer(): Serializer { 21 | return struct( 22 | [ 23 | ['field1', u16()], 24 | ['field2', u32()], 25 | ], 26 | { description: 'MyData' } 27 | ) as Serializer; 28 | } 29 | -------------------------------------------------------------------------------- /clients/js/test/create.test.ts: -------------------------------------------------------------------------------- 1 | import { generateSigner } from '@metaplex-foundation/umi'; 2 | import test from 'ava'; 3 | import { MyAccount, create, fetchMyAccount } from '../src'; 4 | import { createUmi } from './_setup'; 5 | 6 | test('it can create new accounts', async (t) => { 7 | // Given a Umi instance and a new signer. 8 | const umi = await createUmi(); 9 | const address = generateSigner(umi); 10 | 11 | // When we create a new account. 12 | await create(umi, { address, arg1: 1, arg2: 2 }).sendAndConfirm(umi); 13 | 14 | // Then an account was created with the correct data. 15 | t.like(await fetchMyAccount(umi, address.publicKey), { 16 | publicKey: address.publicKey, 17 | authority: umi.identity.publicKey, 18 | data: { field1: 1, field2: 2 }, 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /clients/js/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "./dist", 4 | "baseUrl": ".", 5 | "rootDir": ".", 6 | "target": "ES2020", 7 | "module": "commonjs", 8 | "sourceMap": true, 9 | "declaration": true, 10 | "declarationMap": false, 11 | "removeComments": false, 12 | "moduleResolution": "node", 13 | "noEmit": false, 14 | "preserveWatchOutput": true, 15 | "emitDeclarationOnly": false, 16 | "importHelpers": false, 17 | "strict": true, 18 | "noUnusedLocals": true, 19 | "noFallthroughCasesInSwitch": true, 20 | "downlevelIteration": true, 21 | "esModuleInterop": true, 22 | "allowSyntheticDefaultImports": true, 23 | "incremental": false, 24 | "resolveJsonModule": true, 25 | "skipLibCheck": true, 26 | "useUnknownInCatchVariables": false 27 | }, 28 | "include": ["src", "test", "bench"], 29 | "exclude": ["node_modules", "dist", "build", "lib"] 30 | } 31 | -------------------------------------------------------------------------------- /programs/mpl-project-name/src/instruction.rs: -------------------------------------------------------------------------------- 1 | use borsh::{BorshDeserialize, BorshSerialize}; 2 | use shank::{ShankContext, ShankInstruction}; 3 | 4 | #[derive(BorshDeserialize, BorshSerialize, Clone, Debug, ShankContext, ShankInstruction)] 5 | #[rustfmt::skip] 6 | pub enum MplProjectNameInstruction { 7 | /// Create My Account. 8 | /// A detailed description of the instruction. 9 | #[account(0, writable, signer, name="address", desc = "The address of the new account")] 10 | #[account(1, name="authority", desc = "The authority of the new account")] 11 | #[account(2, writable, signer, name="payer", desc = "The account paying for the storage fees")] 12 | #[account(3, name="system_program", desc = "The system program")] 13 | Create(CreateArgs), 14 | } 15 | 16 | #[repr(C)] 17 | #[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug, Clone)] 18 | pub struct CreateArgs { 19 | /// Some description for arg1. 20 | pub arg1: u16, 21 | /// Some description for arg2. 22 | pub arg2: u32, 23 | } 24 | -------------------------------------------------------------------------------- /clients/rust/src/generated/errors/mpl_project_name.rs: -------------------------------------------------------------------------------- 1 | //! This code was AUTOGENERATED using the kinobi library. 2 | //! Please DO NOT EDIT THIS FILE, instead use visitors 3 | //! to add features, then rerun kinobi to update it. 4 | //! 5 | //! [https://github.com/metaplex-foundation/kinobi] 6 | //! 7 | 8 | use num_derive::FromPrimitive; 9 | use thiserror::Error; 10 | 11 | #[derive(Clone, Debug, Eq, Error, FromPrimitive, PartialEq)] 12 | pub enum MplProjectNameError { 13 | /// 0 (0x0) - Invalid System Program 14 | #[error("Invalid System Program")] 15 | InvalidSystemProgram, 16 | /// 1 (0x1) - Error deserializing account 17 | #[error("Error deserializing account")] 18 | DeserializationError, 19 | /// 2 (0x2) - Error serializing account 20 | #[error("Error serializing account")] 21 | SerializationError, 22 | } 23 | 24 | impl solana_program::program_error::PrintProgramError for MplProjectNameError { 25 | fn print(&self) { 26 | solana_program::msg!(&self.to_string()); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /configs/scripts/program/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) 4 | OUTPUT="./programs/.bin" 5 | # saves external programs binaries to the output directory 6 | source ${SCRIPT_DIR}/dump.sh ${OUTPUT} 7 | # go to parent folder 8 | cd $(dirname $(dirname $(dirname ${SCRIPT_DIR}))) 9 | 10 | if [ -z ${PROGRAMS+x} ]; then 11 | PROGRAMS="$(cat .github/.env | grep "PROGRAMS" | cut -d '=' -f 2)" 12 | fi 13 | 14 | # default to input from the command-line 15 | ARGS=$* 16 | 17 | # command-line arguments override env variable 18 | if [ ! -z "$ARGS" ]; then 19 | PROGRAMS="[\"${1}\"]" 20 | shift 21 | ARGS=$* 22 | fi 23 | 24 | PROGRAMS=$(echo ${PROGRAMS} | jq -c '.[]' | sed 's/"//g') 25 | 26 | # creates the output directory if it doesn't exist 27 | if [ ! -d ${OUTPUT} ]; then 28 | mkdir ${OUTPUT} 29 | fi 30 | 31 | WORKING_DIR=$(pwd) 32 | export SBF_OUT_DIR="${WORKING_DIR}/${OUTPUT}" 33 | 34 | for p in ${PROGRAMS[@]}; do 35 | cd ${WORKING_DIR}/programs/${p} 36 | cargo build-sbf --sbf-out-dir ${WORKING_DIR}/${OUTPUT} $ARGS 37 | done -------------------------------------------------------------------------------- /programs/mpl-project-name/src/error.rs: -------------------------------------------------------------------------------- 1 | use num_derive::FromPrimitive; 2 | use solana_program::{ 3 | decode_error::DecodeError, 4 | msg, 5 | program_error::{PrintProgramError, ProgramError}, 6 | }; 7 | use thiserror::Error; 8 | 9 | #[derive(Error, Clone, Debug, Eq, PartialEq, FromPrimitive)] 10 | pub enum MplProjectNameError { 11 | /// 0 - Invalid System Program 12 | #[error("Invalid System Program")] 13 | InvalidSystemProgram, 14 | /// 1 - Error deserializing account 15 | #[error("Error deserializing account")] 16 | DeserializationError, 17 | /// 2 - Error serializing account 18 | #[error("Error serializing account")] 19 | SerializationError, 20 | } 21 | 22 | impl PrintProgramError for MplProjectNameError { 23 | fn print(&self) { 24 | msg!(&self.to_string()); 25 | } 26 | } 27 | 28 | impl From for ProgramError { 29 | fn from(e: MplProjectNameError) -> Self { 30 | ProgramError::Custom(e as u32) 31 | } 32 | } 33 | 34 | impl DecodeError for MplProjectNameError { 35 | fn type_of() -> &'static str { 36 | "Mpl Project Name Error" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /configs/validator.cjs: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | const programDir = path.join(__dirname, "..", "programs"); 4 | 5 | function getProgram(programBinary) { 6 | return path.join(programDir, ".bin", programBinary); 7 | } 8 | 9 | module.exports = { 10 | validator: { 11 | commitment: "processed", 12 | programs: [ 13 | { 14 | label: "Mpl Project Name", 15 | programId: "MyProgram1111111111111111111111111111111111", 16 | deployPath: getProgram("mpl_project_name_program.so"), 17 | }, 18 | // Below are external programs that should be included in the local validator. 19 | // You may configure which ones to fetch from the cluster when building 20 | // programs within the `configs/program-scripts/dump.sh` script. 21 | { 22 | label: "Token Metadata", 23 | programId: "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s", 24 | deployPath: getProgram("mpl_token_metadata.so"), 25 | }, 26 | { 27 | label: "SPL Noop", 28 | programId: "noopb9bkMVfRPU8AsbpTUg8AQkHtKwMYZiFUjNRtMmV", 29 | deployPath: getProgram("spl_noop.so"), 30 | }, 31 | ], 32 | }, 33 | }; 34 | -------------------------------------------------------------------------------- /configs/scripts/program/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) 4 | OUTPUT="./programs/.bin" 5 | # saves external programs binaries to the output directory 6 | source ${SCRIPT_DIR}/dump.sh ${OUTPUT} 7 | # go to parent folder 8 | cd $(dirname $(dirname $(dirname $SCRIPT_DIR))) 9 | 10 | if [ ! -z "$PROGRAM" ]; then 11 | PROGRAMS='["'${PROGRAM}'"]' 12 | fi 13 | 14 | if [ -z "$PROGRAMS" ]; then 15 | PROGRAMS="$(cat .github/.env | grep "PROGRAMS" | cut -d '=' -f 2)" 16 | fi 17 | 18 | # default to input from the command-line 19 | ARGS=$* 20 | 21 | # command-line arguments override env variable 22 | if [ ! -z "$ARGS" ]; then 23 | PROGRAMS="[\"${1}\"]" 24 | shift 25 | ARGS=$* 26 | fi 27 | 28 | PROGRAMS=$(echo $PROGRAMS | jq -c '.[]' | sed 's/"//g') 29 | 30 | WORKING_DIR=$(pwd) 31 | SOLFMT="solfmt" 32 | export SBF_OUT_DIR="${WORKING_DIR}/${OUTPUT}" 33 | 34 | for p in ${PROGRAMS[@]}; do 35 | cd ${WORKING_DIR}/programs/${p} 36 | 37 | if [ ! "$(command -v $SOLFMT)" = "" ]; then 38 | CARGO_TERM_COLOR=always cargo test-sbf --sbf-out-dir ${WORKING_DIR}/${OUTPUT} ${ARGS} 2>&1 | ${SOLFMT} 39 | else 40 | RUST_LOG=error cargo test-sbf --sbf-out-dir ${WORKING_DIR}/${OUTPUT} ${ARGS} 41 | fi 42 | done -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "programs:build": "./configs/scripts/program/build.sh", 5 | "programs:test": "RUST_LOG=error ./configs/scripts/program/test.sh", 6 | "programs:debug": "./configs/scripts/program/test.sh", 7 | "programs:clean": "./configs/scripts/program/clean.sh", 8 | "clients:rust:test": "./configs/scripts/client/test-rust.sh", 9 | "clients:js:test": "./configs/scripts/client/test-js.sh", 10 | "generate": "pnpm generate:idls && pnpm generate:clients", 11 | "generate:idls": "node ./configs/shank.cjs", 12 | "generate:clients": "node ./configs/kinobi.cjs", 13 | "validator": "CI=1 amman start --config ./configs/validator.cjs", 14 | "validator:debug": "amman start --config ./configs/validator.cjs", 15 | "validator:logs": "CI=1 amman logs", 16 | "validator:stop": "amman stop" 17 | }, 18 | "devDependencies": { 19 | "@metaplex-foundation/amman": "^0.12.1", 20 | "@metaplex-foundation/kinobi": "^0.18.4", 21 | "@metaplex-foundation/shank-js": "^0.1.7", 22 | "typescript": "^4.9.4" 23 | }, 24 | "packageManager": "pnpm@8.9.0", 25 | "dependencies": { 26 | "@metaplex-foundation/umi": "^0.9.2", 27 | "@metaplex-foundation/umi-bundle-tests": "^0.9.2", 28 | "ava": "^6.1.3" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /.github/workflows/test-rust-client.yml: -------------------------------------------------------------------------------- 1 | name: Test Rust Client 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | program_matrix: 7 | type: string 8 | 9 | env: 10 | CACHE: true 11 | 12 | jobs: 13 | test_sdk: 14 | name: Test 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Git checkout 18 | uses: actions/checkout@v3 19 | 20 | - name: Load environment variables 21 | run: cat .github/.env >> $GITHUB_ENV 22 | 23 | - name: Install Rust 24 | uses: metaplex-foundation/actions/install-rust@v1 25 | with: 26 | toolchain: ${{ env.RUST_VERSION }} 27 | 28 | - name: Install Solana 29 | uses: metaplex-foundation/actions/install-solana@v1 30 | with: 31 | version: ${{ env.SOLANA_VERSION }} 32 | cache: ${{ env.CACHE }} 33 | 34 | - name: Cache Rust client test dependencies 35 | uses: metaplex-foundation/actions/cache-crate@v1 36 | with: 37 | folder: ./clients/rust 38 | key: rust-client-test 39 | 40 | - name: Download program builds 41 | uses: actions/download-artifact@v3 42 | with: 43 | name: program-builds 44 | 45 | - name: Run tests 46 | shell: bash 47 | working-directory: configs/scripts/client 48 | run: RUST_LOG=error ./test-rust.sh -------------------------------------------------------------------------------- /.github/file-filters.yml: -------------------------------------------------------------------------------- 1 | # This file is used by the dorny/paths-filter action to figure out if a program or 2 | # client has changed and thus if it should be built or tested. Any changes in the 3 | # files listed below will trigger the appropriate workflow for that program or client. 4 | 5 | # Programs. 6 | 7 | program_common: &program_common 8 | - ".github/workflows/build-programs.yml" 9 | - ".github/workflows/test-programs.yml" 10 | - ".github/workflows/main.yml" 11 | - ".github/file-filters.yml" 12 | - ".github/.env" 13 | 14 | mpl_project_name_program: &mpl_project_name_program 15 | - *program_common 16 | - "programs/mpl-project-name/**" 17 | 18 | programs: &programs 19 | - *mpl_project_name_program 20 | 21 | # Clients. 22 | 23 | client_common: &client_common 24 | - *programs 25 | - ".github/workflows/test-js.yml" 26 | - ".github/workflows/test-rust-client.yml" 27 | - ".github/workflows/build-rust-client.yml" 28 | - ".github/workflows/main.yml" 29 | - ".github/file-filters.yml" 30 | - ".github/.env" 31 | - "configs/shank.cjs" 32 | - "configs/kinobi.cjs" 33 | 34 | js_client: &js_client 35 | - *client_common 36 | - "clients/js/**" 37 | 38 | rust_client: &rust_client 39 | - *client_common 40 | - "clients/rust/**" 41 | 42 | clients: &clients 43 | - *js_client 44 | - *rust_client 45 | 46 | # Any. 47 | 48 | any: &any 49 | - *programs 50 | - *clients 51 | -------------------------------------------------------------------------------- /clients/rust/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to the Rust client 2 | 3 | This is a quick guide to help you contribute to the Rust client of Mpl Project Name. 4 | 5 | ## Getting started 6 | 7 | To build and test the Rust client, you can use `cargo`. 8 | 9 | ```sh 10 | # Build the client 11 | cargo build 12 | 13 | # Test the client (requires building the program first) 14 | cargo test-sbf --sbf-out-dir ../../programs/.bin 15 | ``` 16 | 17 | When something changes in the program(s), make sure to run `pnpm generate` in the root directory, to re-generate the clients accordingly. 18 | 19 | ## Publishing the Rust client 20 | 21 | You can publish a new version of the Rust client crate by manually dispatching the "Publish Rust Client" workflow in the GitHub Actions tab of the repository. 22 | 23 | ![Click on the "Actions" tab, then on the "Publish Rust Client" workflow, then on the "Run workflow" dropdown. Select your options before clicking on the final "Run workflow" button inside the dropdown body.](https://user-images.githubusercontent.com/3642397/235444901-6ee95f30-ed84-4eef-b1c4-8b8474ab82a4.png) 24 | 25 | For this to work, some initial setup is required on the repository as explained below. 26 | 27 | ## Setting up GitHub actions 28 | 29 | To publish Rust clients using GitHub actions, we first need the following secret variable to be set up on the repository. 30 | 31 | - `CRATES_TOKEN` — An access token that can publish your packages to [crates.io](https://crates.io). 32 | -------------------------------------------------------------------------------- /clients/js/README.md: -------------------------------------------------------------------------------- 1 | # JavaScript client for Mpl Project Name 2 | 3 | A Umi-compatible JavaScript library for the project. 4 | 5 | ## Getting started 6 | 7 | 1. First, if you're not already using Umi, [follow these instructions to install the Umi framework](https://github.com/metaplex-foundation/umi/blob/main/docs/installation.md). 8 | 2. Next, install this library using the package manager of your choice. 9 | ```sh 10 | npm install @metaplex-foundation/mpl-project-name 11 | ``` 12 | 2. Finally, register the library with your Umi instance like so. 13 | ```ts 14 | import { mplProjectName } from '@metaplex-foundation/mpl-project-name'; 15 | umi.use(mplProjectName()); 16 | ``` 17 | 18 | You can learn more about this library's API by reading its generated [TypeDoc documentation](https://mpl-project-name-js-docs.vercel.app). 19 | 20 | ## Setting up Benchmarks 21 | The GitHub workflow will automatically run benchmarks on pushes to the `main` branch, however it needs a gh-pages branch to deploy the hosted graph website to. Run the commands below to setup the gh-pages branch. 22 | ```sh 23 | git checkout --orphan gh-pages 24 | git reset --hard 25 | git commit --allow-empty -m "Initializing gh-pages branch" 26 | git push origin gh-pages 27 | git checkout master 28 | ``` 29 | 30 | Afterwards, the webpage will be available at `https://.github.io//dev/bench/` 31 | 32 | ## Contributing 33 | 34 | Check out the [Contributing Guide](./CONTRIBUTING.md) the learn more about how to contribute to this library. 35 | -------------------------------------------------------------------------------- /clients/rust/src/generated/accounts/my_account.rs: -------------------------------------------------------------------------------- 1 | //! This code was AUTOGENERATED using the kinobi library. 2 | //! Please DO NOT EDIT THIS FILE, instead use visitors 3 | //! to add features, then rerun kinobi to update it. 4 | //! 5 | //! [https://github.com/metaplex-foundation/kinobi] 6 | //! 7 | 8 | use crate::generated::types::Key; 9 | use crate::generated::types::MyData; 10 | use borsh::BorshDeserialize; 11 | use borsh::BorshSerialize; 12 | use solana_program::pubkey::Pubkey; 13 | 14 | #[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] 15 | #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 16 | pub struct MyAccount { 17 | pub key: Key, 18 | #[cfg_attr( 19 | feature = "serde", 20 | serde(with = "serde_with::As::") 21 | )] 22 | pub authority: Pubkey, 23 | pub data: MyData, 24 | } 25 | 26 | impl MyAccount { 27 | pub const LEN: usize = 39; 28 | 29 | #[inline(always)] 30 | pub fn from_bytes(data: &[u8]) -> Result { 31 | let mut data = data; 32 | Self::deserialize(&mut data) 33 | } 34 | } 35 | 36 | impl<'a> TryFrom<&solana_program::account_info::AccountInfo<'a>> for MyAccount { 37 | type Error = std::io::Error; 38 | 39 | fn try_from( 40 | account_info: &solana_program::account_info::AccountInfo<'a>, 41 | ) -> Result { 42 | let mut data: &[u8] = &(*account_info.data).borrow(); 43 | Self::deserialize(&mut data) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /clients/js/bench/create.ts: -------------------------------------------------------------------------------- 1 | import { generateSigner } from "@metaplex-foundation/umi"; 2 | // eslint-disable-next-line import/no-extraneous-dependencies 3 | import test from "ava"; 4 | import { existsSync, readFileSync, writeFileSync } from "fs"; 5 | import { create } from '../src'; 6 | import { createUmi } from "./_setup"; 7 | 8 | test('create a new account', async (t) => { 9 | // Given an Umi instance and a new signer. 10 | const umi = await createUmi(); 11 | const address = generateSigner(umi); 12 | 13 | // When we create a new account. 14 | const tx = await create(umi, { address, arg1: 1, arg2: 2 }).sendAndConfirm(umi); 15 | 16 | const compute = Number((await umi.rpc.getTransaction(tx.signature))?.meta.computeUnitsConsumed); 17 | const account = await umi.rpc.getAccount(address.publicKey); 18 | const space = account.exists ? account.data.length : 0; 19 | 20 | const cuResult = { 21 | name: `CU: ${t.title}`, 22 | unit: "Compute Units", 23 | value: compute, 24 | } 25 | 26 | const spaceResult = { 27 | name: `Space: ${t.title}`, 28 | unit: "Bytes", 29 | value: space, 30 | } 31 | 32 | // Read the results array from output.json 33 | let output = []; 34 | if (existsSync("./output.json")) { 35 | output = JSON.parse(readFileSync("./output.json", 'utf-8')); 36 | } 37 | 38 | // Push the result to the array 39 | output.push(cuResult); 40 | output.push(spaceResult); 41 | // Write the array to output.json 42 | writeFileSync("./output.json", JSON.stringify(output, null, 2)); 43 | 44 | t.pass(); 45 | }); 46 | -------------------------------------------------------------------------------- /clients/js/src/generated/programs/mplProjectName.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This code was AUTOGENERATED using the kinobi library. 3 | * Please DO NOT EDIT THIS FILE, instead use visitors 4 | * to add features, then rerun kinobi to update it. 5 | * 6 | * @see https://github.com/metaplex-foundation/kinobi 7 | */ 8 | 9 | import { 10 | ClusterFilter, 11 | Context, 12 | Program, 13 | PublicKey, 14 | } from '@metaplex-foundation/umi'; 15 | import { 16 | getMplProjectNameErrorFromCode, 17 | getMplProjectNameErrorFromName, 18 | } from '../errors'; 19 | 20 | export const MPL_PROJECT_NAME_PROGRAM_ID = 21 | 'MyProgram1111111111111111111111111111111111' as PublicKey<'MyProgram1111111111111111111111111111111111'>; 22 | 23 | export function createMplProjectNameProgram(): Program { 24 | return { 25 | name: 'mplProjectName', 26 | publicKey: MPL_PROJECT_NAME_PROGRAM_ID, 27 | getErrorFromCode(code: number, cause?: Error) { 28 | return getMplProjectNameErrorFromCode(code, this, cause); 29 | }, 30 | getErrorFromName(name: string, cause?: Error) { 31 | return getMplProjectNameErrorFromName(name, this, cause); 32 | }, 33 | isOnCluster() { 34 | return true; 35 | }, 36 | }; 37 | } 38 | 39 | export function getMplProjectNameProgram( 40 | context: Pick, 41 | clusterFilter?: ClusterFilter 42 | ): T { 43 | return context.programs.get('mplProjectName', clusterFilter); 44 | } 45 | 46 | export function getMplProjectNameProgramId( 47 | context: Pick, 48 | clusterFilter?: ClusterFilter 49 | ): PublicKey { 50 | return context.programs.getPublicKey( 51 | 'mplProjectName', 52 | MPL_PROJECT_NAME_PROGRAM_ID, 53 | clusterFilter 54 | ); 55 | } 56 | -------------------------------------------------------------------------------- /clients/rust/tests/create.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "test-sbf")] 2 | 3 | use borsh::BorshDeserialize; 4 | use mpl_project_name::{accounts::MyAccount, instructions::CreateBuilder}; 5 | use solana_program_test::{tokio, ProgramTest}; 6 | use solana_sdk::{ 7 | signature::{Keypair, Signer}, 8 | transaction::Transaction, 9 | }; 10 | 11 | #[tokio::test] 12 | async fn create() { 13 | let mut context = ProgramTest::new("mpl_project_name_program", mpl_project_name::ID, None) 14 | .start_with_context() 15 | .await; 16 | 17 | // Given a new keypair. 18 | 19 | let address = Keypair::new(); 20 | 21 | let ix = CreateBuilder::new() 22 | .address(address.pubkey()) 23 | .authority(context.payer.pubkey()) 24 | .payer(context.payer.pubkey()) 25 | .arg1(1) 26 | .arg2(2) 27 | .instruction(); 28 | 29 | // When we create a new account. 30 | 31 | let tx = Transaction::new_signed_with_payer( 32 | &[ix], 33 | Some(&context.payer.pubkey()), 34 | &[&context.payer, &address], 35 | context.last_blockhash, 36 | ); 37 | context.banks_client.process_transaction(tx).await.unwrap(); 38 | 39 | // Then an account was created with the correct data. 40 | 41 | let account = context 42 | .banks_client 43 | .get_account(address.pubkey()) 44 | .await 45 | .unwrap(); 46 | 47 | assert!(account.is_some()); 48 | 49 | let account = account.unwrap(); 50 | assert_eq!(account.data.len(), MyAccount::LEN); 51 | 52 | let mut account_data = account.data.as_ref(); 53 | let my_account = MyAccount::deserialize(&mut account_data).unwrap(); 54 | assert_eq!(my_account.data.field1, 1); 55 | assert_eq!(my_account.data.field2, 2); 56 | } 57 | -------------------------------------------------------------------------------- /programs/mpl-project-name/src/state.rs: -------------------------------------------------------------------------------- 1 | use borsh::{BorshDeserialize, BorshSerialize}; 2 | use shank::ShankAccount; 3 | use solana_program::account_info::AccountInfo; 4 | use solana_program::entrypoint::ProgramResult; 5 | use solana_program::msg; 6 | use solana_program::program_error::ProgramError; 7 | use solana_program::pubkey::Pubkey; 8 | 9 | use crate::error::MplProjectNameError; 10 | 11 | #[derive(Clone, BorshSerialize, BorshDeserialize, Debug)] 12 | pub enum Key { 13 | Uninitialized, 14 | MyAccount, 15 | MyPdaAccount, 16 | } 17 | 18 | #[repr(C)] 19 | #[derive(Clone, BorshSerialize, BorshDeserialize, Debug, ShankAccount)] 20 | pub struct MyAccount { 21 | pub key: Key, 22 | pub authority: Pubkey, 23 | pub data: MyData, 24 | } 25 | 26 | impl MyAccount { 27 | pub const LEN: usize = 1 + 32 + MyData::LEN; 28 | 29 | pub fn load(account: &AccountInfo) -> Result { 30 | let mut bytes: &[u8] = &(*account.data).borrow(); 31 | MyAccount::deserialize(&mut bytes).map_err(|error| { 32 | msg!("Error: {}", error); 33 | MplProjectNameError::DeserializationError.into() 34 | }) 35 | } 36 | 37 | pub fn save(&self, account: &AccountInfo) -> ProgramResult { 38 | borsh::to_writer(&mut account.data.borrow_mut()[..], self).map_err(|error| { 39 | msg!("Error: {}", error); 40 | MplProjectNameError::SerializationError.into() 41 | }) 42 | } 43 | } 44 | 45 | #[repr(C)] 46 | #[derive(Clone, BorshSerialize, BorshDeserialize, Debug, ShankAccount)] 47 | pub struct MyPdaAccount { 48 | pub key: Key, 49 | pub bump: u8, 50 | } 51 | 52 | #[derive(Clone, BorshSerialize, BorshDeserialize, Debug)] 53 | pub struct MyData { 54 | pub field1: u16, 55 | pub field2: u32, 56 | } 57 | 58 | impl MyData { 59 | pub const LEN: usize = 2 + 4; 60 | } 61 | -------------------------------------------------------------------------------- /.github/workflows/test-programs.yml: -------------------------------------------------------------------------------- 1 | name: Test Programs 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | program_matrix: 7 | type: string 8 | 9 | env: 10 | CACHE: true 11 | 12 | jobs: 13 | test_programs: 14 | name: Test 15 | runs-on: ubuntu-latest 16 | strategy: 17 | matrix: 18 | program: ${{ fromJson(inputs.program_matrix) }} 19 | steps: 20 | - name: Git checkout 21 | uses: actions/checkout@v3 22 | 23 | - name: Load environment variables 24 | run: cat .github/.env >> $GITHUB_ENV 25 | 26 | - name: Install Rust 27 | uses: metaplex-foundation/actions/install-rust@v1 28 | with: 29 | toolchain: ${{ env.RUST_VERSION }} 30 | 31 | - name: Install Solana 32 | uses: metaplex-foundation/actions/install-solana@v1 33 | with: 34 | version: ${{ env.SOLANA_VERSION }} 35 | cache: ${{ env.CACHE }} 36 | 37 | - name: Cache program dependencies 38 | if: env.CACHE == 'true' 39 | uses: metaplex-foundation/actions/cache-program@v1 40 | with: 41 | folder: ./programs/${{ matrix.program }} 42 | key: program-${{ matrix.program }} 43 | 44 | - name: Run cargo fmt 45 | uses: actions-rs/cargo@v1 46 | with: 47 | command: fmt 48 | args: --all --manifest-path ./programs/${{ matrix.program }}/Cargo.toml -- --check 49 | 50 | - name: Run cargo clippy 51 | uses: actions-rs/cargo@v1 52 | with: 53 | command: clippy 54 | args: --all-targets --all-features --no-deps --manifest-path ./programs/${{ matrix.program }}/Cargo.toml 55 | 56 | - name: Run tests 57 | shell: bash 58 | working-directory: configs/scripts/program 59 | run: RUST_LOG=error ./test.sh 60 | env: 61 | PROGRAM: ${{ matrix.program }} 62 | -------------------------------------------------------------------------------- /.github/workflows/build-programs.yml: -------------------------------------------------------------------------------- 1 | name: Build Programs 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | rust: 7 | type: string 8 | solana: 9 | type: string 10 | workflow_dispatch: 11 | inputs: 12 | rust: 13 | description: Rust version 14 | default: 1.70.0 15 | required: true 16 | type: string 17 | solana: 18 | description: Solana version 19 | default: 1.16.17 20 | required: true 21 | type: string 22 | 23 | env: 24 | CACHE: true 25 | 26 | jobs: 27 | build_programs: 28 | name: Build 29 | runs-on: ubuntu-latest 30 | steps: 31 | - name: Git checkout 32 | uses: actions/checkout@v3 33 | 34 | - name: Load environment variables 35 | run: cat .github/.env >> $GITHUB_ENV 36 | 37 | - name: Install Rust 38 | uses: metaplex-foundation/actions/install-rust@v1 39 | with: 40 | toolchain: ${{ inputs.rust || env.RUST_VERSION }} 41 | 42 | - name: Install Solana 43 | uses: metaplex-foundation/actions/install-solana@v1 44 | with: 45 | version: ${{ inputs.solana || env.SOLANA_VERSION }} 46 | cache: ${{ env.CACHE }} 47 | 48 | - name: Cache program dependencies 49 | if: env.CACHE == 'true' 50 | uses: metaplex-foundation/actions/cache-programs@v1 51 | 52 | - name: Build programs 53 | shell: bash 54 | working-directory: configs/scripts/program 55 | run: ./build.sh 56 | env: 57 | PROGRAMS: ${{ env.PROGRAMS }} 58 | 59 | - name: Upload program builds 60 | uses: actions/upload-artifact@v3 61 | with: 62 | name: program-builds 63 | # First wildcard ensures exported paths are consistently under the programs folder. 64 | path: ./program*/.bin/*.so 65 | if-no-files-found: error 66 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | Solana Project Template 3 |

4 |

5 | A template for vanilla Solana programs and their clients. 6 |

7 |

8 | Solana Project Template 9 |

10 |

11 | 12 |

13 | 14 | ## Features 15 | 16 | - **Generate IDLs** using [Shank](https://github.com/metaplex-foundation/shank) 17 | - **Generate clients** for one or more programs using [Kinobi](https://github.com/metaplex-foundation/kinobi) 18 | - Configure **local validators** using [Amman](https://github.com/metaplex-foundation/amman) 19 | - **Build, test and lint** programs and clients using GitHub Actions. 20 | - **Publish** your [Umi](https://github.com/metaplex-foundation/umi) JavaScript client and its TypeScript documentation by dispatching a GitHub workflow. 21 | - **Publish** your Rust client SDK to [crates.io](https://crates.io) by dispatching a GitHub workflow. 22 | 23 | ## Getting started 24 | 25 | 1. [Use this template](https://github.com/new?template_name=solana-project-template&template_owner=metaplex-foundation) to create a new repository. 26 | 2. Open the `init.sh` script and update the following variables. 27 | ```sh 28 | NAME="mpl-project-name" 29 | DESCRIPTION="My project description" 30 | PUBLIC_KEY="MyProgram1111111111111111111111111111111111" 31 | ``` 32 | 3. Run the `init.sh` script to initialize the project. This will find/replace the variable above, rename some files/folders, update the README and, finally, remove the `init.sh` script. 33 | ```sh 34 | ./init.sh 35 | ``` 36 | 4. [Read the `CONTRIBUTING.md` file](./CONTRIBUTING.md) to learn more about how to use the project. 37 | -------------------------------------------------------------------------------- /configs/kinobi.cjs: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const k = require("@metaplex-foundation/kinobi"); 3 | 4 | // Paths. 5 | const clientDir = path.join(__dirname, "..", "clients"); 6 | const idlDir = path.join(__dirname, "..", "idls"); 7 | 8 | // Instanciate Kinobi. 9 | const kinobi = k.createFromIdls([path.join(idlDir, "mpl_project_name_program.json")]); 10 | 11 | // Update programs. 12 | kinobi.update( 13 | new k.updateProgramsVisitor({ 14 | mplProjectNameProgram: { name: "mplProjectName" }, 15 | }) 16 | ); 17 | 18 | // Update accounts. 19 | kinobi.update( 20 | new k.updateAccountsVisitor({ 21 | myPdaAccount: { 22 | seeds: [ 23 | k.constantPdaSeedNodeFromString("myPdaAccount"), 24 | k.programIdPdaSeedNode(), 25 | k.variablePdaSeedNode("authority", k.publicKeyTypeNode(), "The address of the authority"), 26 | k.variablePdaSeedNode("name", k.stringTypeNode(), "The name of the account"), 27 | ], 28 | }, 29 | }) 30 | ); 31 | 32 | // Update instructions. 33 | kinobi.update( 34 | new k.updateInstructionsVisitor({ 35 | create: { 36 | byteDeltas: [ 37 | k.instructionByteDeltaNode(k.accountLinkNode("myAccount")), 38 | ], 39 | }, 40 | }) 41 | ); 42 | 43 | // Set ShankAccount discriminator. 44 | const key = (name) => ({ field: "key", value: k.enumValueNode("Key", name) }); 45 | kinobi.update( 46 | new k.setAccountDiscriminatorFromFieldVisitor({ 47 | myAccount: key("MyAccount"), 48 | myPdaAccount: key("MyPdaAccount"), 49 | }) 50 | ); 51 | 52 | // Render JavaScript. 53 | const jsDir = path.join(clientDir, "js", "src", "generated"); 54 | const prettier = require(path.join(clientDir, "js", ".prettierrc.json")); 55 | kinobi.accept(new k.renderJavaScriptVisitor(jsDir, { prettier })); 56 | 57 | // Render Rust. 58 | const crateDir = path.join(clientDir, "rust"); 59 | const rustDir = path.join(clientDir, "rust", "src", "generated"); 60 | kinobi.accept( 61 | new k.renderRustVisitor(rustDir, { 62 | formatCode: true, 63 | crateFolder: crateDir, 64 | }) 65 | ); 66 | -------------------------------------------------------------------------------- /.github/workflows/test-js-client.yml: -------------------------------------------------------------------------------- 1 | name: Test JS client 2 | 3 | on: 4 | workflow_call: 5 | 6 | env: 7 | CACHE: true 8 | 9 | jobs: 10 | test: 11 | name: Test 12 | runs-on: ubuntu-latest 13 | strategy: 14 | matrix: 15 | node: ["16.x", "18.x"] 16 | steps: 17 | - name: Git checkout 18 | uses: actions/checkout@v3 19 | 20 | - name: Load environment variables 21 | run: cat .github/.env >> $GITHUB_ENV 22 | 23 | - name: Start validator 24 | uses: metaplex-foundation/actions/start-validator@v1 25 | with: 26 | node: ${{ matrix.node }} 27 | solana: ${{ env.SOLANA_VERSION }} 28 | cache: ${{ env.CACHE }} 29 | 30 | - name: Install dependencies 31 | uses: metaplex-foundation/actions/install-node-dependencies@v1 32 | with: 33 | folder: ./clients/js 34 | cache: ${{ env.CACHE }} 35 | key: clients-js 36 | 37 | - name: Build 38 | working-directory: ./clients/js 39 | run: pnpm build 40 | 41 | - name: Test 42 | working-directory: ./clients/js 43 | run: pnpm test 44 | 45 | lint: 46 | name: Lint 47 | runs-on: ubuntu-latest 48 | steps: 49 | - name: Git checkout 50 | uses: actions/checkout@v3 51 | 52 | - name: Load environment variables 53 | run: cat .github/.env >> $GITHUB_ENV 54 | 55 | - name: Install Node.js 56 | uses: metaplex-foundation/actions/install-node-with-pnpm@v1 57 | with: 58 | version: ${{ env.NODE_VERSION }} 59 | cache: ${{ env.CACHE }} 60 | 61 | - name: Install dependencies 62 | uses: metaplex-foundation/actions/install-node-dependencies@v1 63 | with: 64 | folder: ./clients/js 65 | cache: ${{ env.CACHE }} 66 | key: clients-js 67 | 68 | - name: Format 69 | working-directory: ./clients/js 70 | run: pnpm format 71 | 72 | - name: Lint 73 | working-directory: ./clients/js 74 | run: pnpm lint 75 | -------------------------------------------------------------------------------- /.github/workflows/build-rust-client.yml: -------------------------------------------------------------------------------- 1 | name: Build Rust Client 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | rust: 7 | type: string 8 | solana: 9 | type: string 10 | workflow_dispatch: 11 | inputs: 12 | rust: 13 | description: Rust version 14 | default: 1.70.0 15 | required: true 16 | type: string 17 | solana: 18 | description: Solana version 19 | default: 1.16.17 20 | required: true 21 | type: string 22 | 23 | env: 24 | CACHE: true 25 | 26 | jobs: 27 | build_sdk: 28 | name: Build 29 | runs-on: ubuntu-latest 30 | steps: 31 | - name: Git checkout 32 | uses: actions/checkout@v3 33 | 34 | - name: Load environment variables 35 | run: cat .github/.env >> $GITHUB_ENV 36 | 37 | - name: Install Rust 38 | uses: metaplex-foundation/actions/install-rust@v1 39 | with: 40 | toolchain: ${{ inputs.rust || env.RUST_VERSION }} 41 | 42 | - name: Install Solana 43 | uses: metaplex-foundation/actions/install-solana@v1 44 | with: 45 | version: ${{ inputs.solana || env.SOLANA_VERSION }} 46 | cache: ${{ env.CACHE }} 47 | 48 | - name: Cache Rust client test dependencies 49 | uses: metaplex-foundation/actions/cache-crate@v1 50 | with: 51 | folder: ./clients/rust 52 | key: rust-client-test 53 | 54 | - name: Run cargo clippy 55 | uses: actions-rs/cargo@v1 56 | with: 57 | command: clippy 58 | args: --all-targets --all-features --no-deps --manifest-path ./clients/rust/Cargo.toml 59 | 60 | - name: Build Rust client 61 | shell: bash 62 | working-directory: clients/rust 63 | run: cargo build --all-features --release 64 | 65 | - name: Upload Rust client builds 66 | uses: actions/upload-artifact@v3 67 | with: 68 | name: rust-client-builds 69 | # First wildcard ensures exported paths are consistently under the clients folder. 70 | path: ./targe*/release/*mpl_project_name* 71 | if-no-files-found: error -------------------------------------------------------------------------------- /clients/js/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@metaplex-foundation/mpl-project-name", 3 | "version": "0.1.0", 4 | "description": "My project description", 5 | "main": "dist/src/index.js", 6 | "types": "dist/src/index.d.ts", 7 | "scripts": { 8 | "build": "rimraf dist && tsc -p tsconfig.json", 9 | "build:docs": "typedoc", 10 | "test": "ava", 11 | "bench": "rm -f output.json && ava ./dist/bench/*.js --serial --no-worker-threads", 12 | "lint": "eslint --ext js,ts,tsx src", 13 | "lint:fix": "eslint --fix --ext js,ts,tsx src", 14 | "format": "prettier --check src test", 15 | "format:fix": "prettier --write src test" 16 | }, 17 | "files": [ 18 | "/dist/src" 19 | ], 20 | "publishConfig": { 21 | "access": "public", 22 | "registry": "https://registry.npmjs.org" 23 | }, 24 | "homepage": "https://metaplex.com", 25 | "repository": "https://github.com/metaplex-foundation/mpl-project-name.git", 26 | "author": "Metaplex Maintainers ", 27 | "license": "Apache-2.0", 28 | "dependencies": { 29 | "@metaplex-foundation/mpl-toolbox": "^0.8.0" 30 | }, 31 | "peerDependencies": { 32 | "@metaplex-foundation/umi": "^0.8.2" 33 | }, 34 | "devDependencies": { 35 | "@ava/typescript": "^3.0.1", 36 | "@metaplex-foundation/umi": "^0.8.2", 37 | "@metaplex-foundation/umi-bundle-tests": "^0.8.2", 38 | "@solana/web3.js": "^1.73.0", 39 | "@typescript-eslint/eslint-plugin": "^5.0.0", 40 | "@typescript-eslint/parser": "^5.46.1", 41 | "ava": "^5.1.0", 42 | "eslint": "^8.0.1", 43 | "eslint-config-airbnb-typescript": "^17.0.0", 44 | "eslint-config-prettier": "^8.5.0", 45 | "eslint-plugin-import": "^2.26.0", 46 | "eslint-plugin-prettier": "^4.2.1", 47 | "prettier": "^2.5.1", 48 | "rimraf": "^3.0.2", 49 | "typedoc": "^0.23.16", 50 | "typedoc-plugin-expand-object-like-types": "^0.1.1", 51 | "typedoc-plugin-missing-exports": "^1.0.0", 52 | "typescript": "^4.6.2", 53 | "vercel": "^28.16.0" 54 | }, 55 | "ava": { 56 | "typescript": { 57 | "compile": false, 58 | "rewritePaths": { 59 | "src/": "dist/src/", 60 | "test/": "dist/test/", 61 | "bench/": "dist/bench/" 62 | } 63 | } 64 | }, 65 | "packageManager": "pnpm@8.2.0" 66 | } 67 | -------------------------------------------------------------------------------- /programs/mpl-project-name/src/processor.rs: -------------------------------------------------------------------------------- 1 | use borsh::BorshDeserialize; 2 | use solana_program::{ 3 | account_info::AccountInfo, entrypoint::ProgramResult, msg, program::invoke, pubkey::Pubkey, 4 | rent::Rent, system_instruction, system_program, sysvar::Sysvar, 5 | }; 6 | 7 | use crate::error::MplProjectNameError; 8 | use crate::instruction::accounts::CreateAccounts; 9 | use crate::instruction::{CreateArgs, MplProjectNameInstruction}; 10 | use crate::state::{Key, MyAccount, MyData}; 11 | 12 | pub fn process_instruction<'a>( 13 | _program_id: &Pubkey, 14 | accounts: &'a [AccountInfo<'a>], 15 | instruction_data: &[u8], 16 | ) -> ProgramResult { 17 | let instruction: MplProjectNameInstruction = 18 | MplProjectNameInstruction::try_from_slice(instruction_data)?; 19 | match instruction { 20 | MplProjectNameInstruction::Create(args) => { 21 | msg!("Instruction: Create"); 22 | create(accounts, args) 23 | } 24 | } 25 | } 26 | 27 | fn create<'a>(accounts: &'a [AccountInfo<'a>], args: CreateArgs) -> ProgramResult { 28 | // Accounts. 29 | let ctx = CreateAccounts::context(accounts)?; 30 | let rent = Rent::get()?; 31 | 32 | // Guards. 33 | if *ctx.accounts.system_program.key != system_program::id() { 34 | return Err(MplProjectNameError::InvalidSystemProgram.into()); 35 | } 36 | 37 | // Fetch the space and minimum lamports required for rent exemption. 38 | let space: usize = MyAccount::LEN; 39 | let lamports: u64 = rent.minimum_balance(space); 40 | 41 | // CPI to the System Program. 42 | invoke( 43 | &system_instruction::create_account( 44 | ctx.accounts.payer.key, 45 | ctx.accounts.address.key, 46 | lamports, 47 | space as u64, 48 | &crate::id(), 49 | ), 50 | &[ 51 | ctx.accounts.payer.clone(), 52 | ctx.accounts.address.clone(), 53 | ctx.accounts.system_program.clone(), 54 | ], 55 | )?; 56 | 57 | let my_account = MyAccount { 58 | key: Key::MyAccount, 59 | authority: *ctx.accounts.authority.key, 60 | data: MyData { 61 | field1: args.arg1, 62 | field2: args.arg2, 63 | }, 64 | }; 65 | 66 | my_account.save(ctx.accounts.address) 67 | } 68 | -------------------------------------------------------------------------------- /.github/workflows/benchmark.yml: -------------------------------------------------------------------------------- 1 | name: Benchmark 2 | on: 3 | workflow_call: 4 | 5 | permissions: 6 | # deployments permission to deploy GitHub pages website 7 | deployments: write 8 | # contents permission to update benchmark contents in gh-pages branch 9 | contents: write 10 | 11 | env: 12 | CACHE: true 13 | 14 | jobs: 15 | benchmark: 16 | name: Performance regression check 17 | runs-on: ubuntu-latest 18 | steps: 19 | - name: Git checkout 20 | uses: actions/checkout@v3 21 | 22 | - name: Load environment variables 23 | run: cat .github/.env >> $GITHUB_ENV 24 | 25 | - name: Start validator 26 | uses: metaplex-foundation/actions/start-validator@v1 27 | with: 28 | node: 18.x 29 | solana: ${{ env.SOLANA_VERSION }} 30 | cache: ${{ env.CACHE }} 31 | 32 | - name: Install dependencies 33 | uses: metaplex-foundation/actions/install-node-dependencies@v1 34 | with: 35 | folder: ./clients/js 36 | cache: ${{ env.CACHE }} 37 | key: clients-js 38 | 39 | - name: Build 40 | working-directory: ./clients/js 41 | run: pnpm build 42 | 43 | - name: Test 44 | working-directory: ./clients/js 45 | run: pnpm bench 46 | 47 | # Download previous benchmark result from cache (if exists) 48 | - name: Download previous benchmark data 49 | uses: actions/cache@v4 50 | with: 51 | path: ./cache 52 | key: ${{ runner.os }}-benchmark 53 | 54 | # Run `github-action-benchmark` action 55 | - name: Store benchmark result 56 | uses: benchmark-action/github-action-benchmark@v1 57 | with: 58 | # What benchmark tool the output.json came from 59 | tool: "customSmallerIsBetter" 60 | # Where the output from the benchmark tool is stored 61 | output-file-path: ./clients/js/output.json 62 | # Where the previous data file is stored 63 | # external-data-json-path: ./cache/benchmark-data.json 64 | # Workflow will fail when an alert happens 65 | fail-on-alert: true 66 | # Access token to deploy GitHub Pages branch 67 | github-token: ${{ secrets.GITHUB_TOKEN }} 68 | # Push and deploy GitHub pages branch automatically 69 | auto-push: true 70 | -------------------------------------------------------------------------------- /configs/scripts/program/dump.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | EXTERNAL_ID=("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s" "noopb9bkMVfRPU8AsbpTUg8AQkHtKwMYZiFUjNRtMmV") 4 | EXTERNAL_SO=("mpl_token_metadata.so" "spl_noop.so") 5 | 6 | # output colours 7 | RED() { echo $'\e[1;31m'$1$'\e[0m'; } 8 | GRN() { echo $'\e[1;32m'$1$'\e[0m'; } 9 | YLW() { echo $'\e[1;33m'$1$'\e[0m'; } 10 | 11 | CURRENT_DIR=$(pwd) 12 | SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) 13 | # go to parent folder 14 | cd $(dirname $(dirname $(dirname $SCRIPT_DIR))) 15 | 16 | OUTPUT=$1 17 | 18 | if [ -z ${RPC+x} ]; then 19 | RPC="https://api.mainnet-beta.solana.com" 20 | fi 21 | 22 | if [ -z "$OUTPUT" ]; then 23 | echo "missing output directory" 24 | exit 1 25 | fi 26 | 27 | # creates the output directory if it doesn't exist 28 | if [ ! -d ${OUTPUT} ]; then 29 | mkdir ${OUTPUT} 30 | fi 31 | 32 | # only prints this if we have external programs 33 | if [ ${#EXTERNAL_ID[@]} -gt 0 ]; then 34 | echo "Dumping external accounts to '${OUTPUT}':" 35 | fi 36 | 37 | # copy external programs or accounts binaries from the chain 38 | copy_from_chain() { 39 | ACCOUNT_TYPE=`echo $1 | cut -d. -f2` 40 | PREFIX=$2 41 | 42 | case "$ACCOUNT_TYPE" in 43 | "bin") 44 | solana account -u $RPC ${EXTERNAL_ID[$i]} -o ${OUTPUT}/$2$1 > /dev/null 45 | ;; 46 | "so") 47 | solana program dump -u $RPC ${EXTERNAL_ID[$i]} ${OUTPUT}/$2$1 > /dev/null 48 | ;; 49 | *) 50 | echo $(RED "[ ERROR ] unknown account type for '$1'") 51 | exit 1 52 | ;; 53 | esac 54 | 55 | if [ -z "$PREFIX" ]; then 56 | echo "Wrote account data to ${OUTPUT}/$2$1" 57 | fi 58 | } 59 | 60 | # dump external programs binaries if needed 61 | for i in ${!EXTERNAL_ID[@]}; do 62 | if [ ! -f "${OUTPUT}/${EXTERNAL_SO[$i]}" ]; then 63 | copy_from_chain "${EXTERNAL_SO[$i]}" 64 | else 65 | copy_from_chain "${EXTERNAL_SO[$i]}" "onchain-" 66 | 67 | ON_CHAIN=`sha256sum -b ${OUTPUT}/onchain-${EXTERNAL_SO[$i]} | cut -d ' ' -f 1` 68 | LOCAL=`sha256sum -b ${OUTPUT}/${EXTERNAL_SO[$i]} | cut -d ' ' -f 1` 69 | 70 | if [ "$ON_CHAIN" != "$LOCAL" ]; then 71 | echo $(YLW "[ WARNING ] on-chain and local binaries are different for '${EXTERNAL_SO[$i]}'") 72 | else 73 | echo "$(GRN "[ SKIPPED ]") on-chain and local binaries are the same for '${EXTERNAL_SO[$i]}'" 74 | fi 75 | 76 | rm ${OUTPUT}/onchain-${EXTERNAL_SO[$i]} 77 | fi 78 | done 79 | 80 | # only prints this if we have external programs 81 | if [ ${#EXTERNAL_ID[@]} -gt 0 ]; then 82 | echo "" 83 | fi 84 | 85 | cd ${CURRENT_DIR} -------------------------------------------------------------------------------- /clients/js/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to the JavaScript client 2 | 3 | This is a quick guide to help you contribute to the JavaScript client of Mpl Project Name. 4 | 5 | ## Getting started 6 | 7 | [Ensure you have pnpm installed](https://pnpm.io/installation) and run the following command to install the client's dependencies. 8 | 9 | ```sh 10 | pnpm install 11 | ``` 12 | 13 | You can then run the following commands to build, test and lint the client. 14 | 15 | ```sh 16 | # Build the client. 17 | pnpm build 18 | 19 | # Test the client (requires building first). 20 | pnpm build && pnpm test 21 | 22 | # Test a specific file or set of files. 23 | pnpm build && pnpm test test/somefile.test.js 24 | pnpm build && pnpm test test/somePattern* 25 | 26 | # Lint and/or format the client. 27 | pnpm lint:fix 28 | pnpm format:fix 29 | ``` 30 | 31 | When something changes in the program(s), make sure to run `pnpm generate` in the root directory, to re-generate the clients accordingly. 32 | 33 | ## Publishing the JavaScript client 34 | 35 | You can publish a new version of the JavaScript client by manually dispatching the "Publish JS Client" workflow in the GitHub Actions tab of the repository. 36 | 37 | ![Click on the "Actions" tab, then on the "Publish JS Client" workflow, then on the "Run workflow" dropdown. Select your options before clicking on the final "Run workflow" button inside the dropdown body.](https://user-images.githubusercontent.com/3642397/235444901-6ee95f30-ed84-4eef-b1c4-8b8474ab82a4.png) 38 | 39 | For this to work, some initial setup is required on the repository as explained below. 40 | 41 | ## Setting up GitHub actions 42 | 43 | To publish JavaScript clients using GitHub actions, we first need the following secret variables to be set up on the repository. 44 | 45 | - `NPM_TOKEN` — An access token that can publish your packages to NPM. 46 | - `VERCEL_TOKEN` — An access token that can deploy to Vercel. 47 | - `VERCEL_ORG_ID` — The ID of the Vercel organization you want to deploy to. 48 | 49 | Then, we'll need to create a new GitHub environment called `js-client-documentation` for the generated documentation of the JavaScript client. We can then select the `main` branch only and add the following secret variable to this specific environment. 50 | 51 | - `VERCEL_PROJECT_ID` — The ID of the Vercel project you want to deploy to. 52 | The convention for Metaplex is to create a new Vercel project named `mpl-project-name-js-docs` with the following deployment settings: 53 | 54 | - Build Command: `pnpm run build:docs` 55 | - Output Directory: `docs` 56 | - Install Command: `pnpm install` 57 | - Development Command: _None_ 58 | 59 | With all that set up, you can now run the "Publish JS Client" workflow by dispatching it from the GitHub UI. 60 | -------------------------------------------------------------------------------- /clients/rust/src/generated/accounts/my_pda_account.rs: -------------------------------------------------------------------------------- 1 | //! This code was AUTOGENERATED using the kinobi library. 2 | //! Please DO NOT EDIT THIS FILE, instead use visitors 3 | //! to add features, then rerun kinobi to update it. 4 | //! 5 | //! [https://github.com/metaplex-foundation/kinobi] 6 | //! 7 | 8 | use crate::generated::types::Key; 9 | use borsh::BorshDeserialize; 10 | use borsh::BorshSerialize; 11 | use solana_program::pubkey::Pubkey; 12 | 13 | #[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] 14 | #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 15 | pub struct MyPdaAccount { 16 | pub key: Key, 17 | pub bump: u8, 18 | } 19 | 20 | impl MyPdaAccount { 21 | pub const LEN: usize = 2; 22 | 23 | /// Prefix values used to generate a PDA for this account. 24 | /// 25 | /// Values are positional and appear in the following order: 26 | /// 27 | /// 0. `MyPdaAccount::PREFIX` 28 | /// 1. `crate::MPL_PROJECT_NAME_ID` 29 | /// 2. authority (`Pubkey`) 30 | /// 3. name (`String`) 31 | pub const PREFIX: &'static [u8] = "myPdaAccount".as_bytes(); 32 | 33 | pub fn create_pda( 34 | authority: Pubkey, 35 | name: String, 36 | bump: u8, 37 | ) -> Result { 38 | solana_program::pubkey::Pubkey::create_program_address( 39 | &[ 40 | "myPdaAccount".as_bytes(), 41 | crate::MPL_PROJECT_NAME_ID.as_ref(), 42 | authority.as_ref(), 43 | name.to_string().as_ref(), 44 | &[bump], 45 | ], 46 | &crate::MPL_PROJECT_NAME_ID, 47 | ) 48 | } 49 | 50 | pub fn find_pda(authority: &Pubkey, name: String) -> (solana_program::pubkey::Pubkey, u8) { 51 | solana_program::pubkey::Pubkey::find_program_address( 52 | &[ 53 | "myPdaAccount".as_bytes(), 54 | crate::MPL_PROJECT_NAME_ID.as_ref(), 55 | authority.as_ref(), 56 | name.to_string().as_ref(), 57 | ], 58 | &crate::MPL_PROJECT_NAME_ID, 59 | ) 60 | } 61 | 62 | #[inline(always)] 63 | pub fn from_bytes(data: &[u8]) -> Result { 64 | let mut data = data; 65 | Self::deserialize(&mut data) 66 | } 67 | } 68 | 69 | impl<'a> TryFrom<&solana_program::account_info::AccountInfo<'a>> for MyPdaAccount { 70 | type Error = std::io::Error; 71 | 72 | fn try_from( 73 | account_info: &solana_program::account_info::AccountInfo<'a>, 74 | ) -> Result { 75 | let mut data: &[u8] = &(*account_info.data).borrow(); 76 | Self::deserialize(&mut data) 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Mpl Project Name 2 | 3 | This is a quick guide to help you contribute to Mpl Project Name. 4 | 5 | ## Getting started 6 | 7 | The root folder has a private `package.json` containing a few scripts and JavaScript dependencies that help generate IDLs; clients and start a local validator. First, [ensure you have pnpm installed](https://pnpm.io/installation) and run the following command to install the dependencies. 8 | 9 | ```sh 10 | pnpm install 11 | ``` 12 | 13 | You will then have access to the following commands. 14 | 15 | - `pnpm programs:build` - Build all programs and fetch all dependant programs. 16 | - `pnpm programs:test` - Test all programs. 17 | - `pnpm programs:debug` - Test all programs with logs enabled. 18 | - `pnpm programs:clean` - Clean all built and fetched programs. 19 | - `pnpm clients:rust:test` - Run the Rust client tests. 20 | - `pnpm clients:js:test` - Run the JS client tests. 21 | - `pnpm generate` - Shortcut for `pnpm generate:idls && pnpm generate:clients`. 22 | - `pnpm generate:idls` - Generate IDLs for all programs, as configured in the `configs/shank.cjs` file. 23 | - `pnpm generate:clients` - Generate clients using Kinobi, as configured in the `configs/kinobi.cjs` file. 24 | - `pnpm validator` - Start a local validator using Amman, as configured in the `configs/validator.cjs` file. 25 | - `pnpm validator:debug` - Start a local validator using Amman with logs enabled, as configured in the `configs/validator.cjs` file. 26 | - `pnpm validator:stop` - Stop the local validator. 27 | - `pnpm validator:logs` - Show the logs of the local validator. 28 | 29 | ## Managing clients 30 | 31 | Each client has its own README with instructions on how to get started. You can find them in the `clients` folder. 32 | 33 | - [JavaScript client](./clients/js/README.md) 34 | - [Rust client](./clients/rust/README.md) 35 | 36 | In order to generate the clients, run the following command. 37 | 38 | ```sh 39 | pnpm generate 40 | ``` 41 | 42 | You will need to run `pnpm generate` to re-generate the clients when something changes in the program(s). 43 | 44 | ## Setting up CI/CD using GitHub actions 45 | 46 | Most of the CI/CD should already be set up for you and the `.github/.env` file can be used to tweak the variables of the workflows. 47 | 48 | However, the "Publish JS Client" workflow — configured in `.github/workflows/publish-js-client.yml` — requires a few more steps to work. See the [CONTRIBUTING.md file of the JavaScript client](./clients/js/CONTRIBUTING.md#setting-up-github-actions) for more information. 49 | 50 | Similarly, the "Publish Rust Client" workflow — configured in `.github/workflows/publish-rust-client.yml` — requires a few more steps to work. See the [CONTRIBUTING.md file of the Rust client](./clients/rust/CONTRIBUTING.md#setting-up-github-actions) for more information. 51 | -------------------------------------------------------------------------------- /clients/js/src/generated/errors/mplProjectName.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This code was AUTOGENERATED using the kinobi library. 3 | * Please DO NOT EDIT THIS FILE, instead use visitors 4 | * to add features, then rerun kinobi to update it. 5 | * 6 | * @see https://github.com/metaplex-foundation/kinobi 7 | */ 8 | 9 | import { Program, ProgramError } from '@metaplex-foundation/umi'; 10 | 11 | type ProgramErrorConstructor = new ( 12 | program: Program, 13 | cause?: Error 14 | ) => ProgramError; 15 | const codeToErrorMap: Map = new Map(); 16 | const nameToErrorMap: Map = new Map(); 17 | 18 | /** InvalidSystemProgram: Invalid System Program */ 19 | export class InvalidSystemProgramError extends ProgramError { 20 | override readonly name: string = 'InvalidSystemProgram'; 21 | 22 | readonly code: number = 0x0; // 0 23 | 24 | constructor(program: Program, cause?: Error) { 25 | super('Invalid System Program', program, cause); 26 | } 27 | } 28 | codeToErrorMap.set(0x0, InvalidSystemProgramError); 29 | nameToErrorMap.set('InvalidSystemProgram', InvalidSystemProgramError); 30 | 31 | /** DeserializationError: Error deserializing account */ 32 | export class DeserializationErrorError extends ProgramError { 33 | override readonly name: string = 'DeserializationError'; 34 | 35 | readonly code: number = 0x1; // 1 36 | 37 | constructor(program: Program, cause?: Error) { 38 | super('Error deserializing account', program, cause); 39 | } 40 | } 41 | codeToErrorMap.set(0x1, DeserializationErrorError); 42 | nameToErrorMap.set('DeserializationError', DeserializationErrorError); 43 | 44 | /** SerializationError: Error serializing account */ 45 | export class SerializationErrorError extends ProgramError { 46 | override readonly name: string = 'SerializationError'; 47 | 48 | readonly code: number = 0x2; // 2 49 | 50 | constructor(program: Program, cause?: Error) { 51 | super('Error serializing account', program, cause); 52 | } 53 | } 54 | codeToErrorMap.set(0x2, SerializationErrorError); 55 | nameToErrorMap.set('SerializationError', SerializationErrorError); 56 | 57 | /** 58 | * Attempts to resolve a custom program error from the provided error code. 59 | * @category Errors 60 | */ 61 | export function getMplProjectNameErrorFromCode( 62 | code: number, 63 | program: Program, 64 | cause?: Error 65 | ): ProgramError | null { 66 | const constructor = codeToErrorMap.get(code); 67 | return constructor ? new constructor(program, cause) : null; 68 | } 69 | 70 | /** 71 | * Attempts to resolve a custom program error from the provided error name, i.e. 'Unauthorized'. 72 | * @category Errors 73 | */ 74 | export function getMplProjectNameErrorFromName( 75 | name: string, 76 | program: Program, 77 | cause?: Error 78 | ): ProgramError | null { 79 | const constructor = nameToErrorMap.get(name); 80 | return constructor ? new constructor(program, cause) : null; 81 | } 82 | -------------------------------------------------------------------------------- /init.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # This script renames the default project name, description and 4 | # public key with the provided values. Simply update the values 5 | # below, run "./init.sh" in your terminal and you're good to go! 6 | 7 | NAME="mpl-project-name" 8 | DESCRIPTION="My project description" 9 | PUBLIC_KEY="MyProgram1111111111111111111111111111111111" 10 | 11 | # ------------------------------------ 12 | # --- Do not edit below this line. --- 13 | # ------------------------------------ 14 | 15 | # Initial variables 16 | ROOT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) 17 | OLD_NAME="mpl-project-name" 18 | OLD_DESCRIPTION="My project description" 19 | OLD_PUBLIC_KEY="MyProgram1111111111111111111111111111111111" 20 | 21 | # snake_case 22 | SNAKE_NAME=$(echo "$NAME" | perl -pe 's/-/_/g') 23 | SNAKE_OLD_NAME=$(echo "$OLD_NAME" | perl -pe 's/-/_/g') 24 | 25 | # CAPITALIZED_SNAKE_CASE 26 | CAPITALIZED_SNAKE_NAME=$(echo "$SNAKE_NAME" | tr '[:lower:]' '[:upper:]') 27 | CAPITALIZED_SNAKE_OLD_NAME=$(echo "$SNAKE_OLD_NAME" | tr '[:lower:]' '[:upper:]') 28 | 29 | # camelCase 30 | CAMEL_NAME=$(echo "$NAME" | perl -pe 's/-(\w)/\U$1/g') 31 | CAMEL_OLD_NAME=$(echo "$OLD_NAME" | perl -pe 's/-(\w)/\U$1/g') 32 | 33 | # PascalCase 34 | PASCAL_NAME=$(echo "$NAME" | perl -pe 's/(^|-)(\w)/\U$2/g') 35 | PASCAL_OLD_NAME=$(echo "$OLD_NAME" | perl -pe 's/(^|-)(\w)/\U$2/g') 36 | 37 | # Title Case 38 | TITLE_NAME=$(echo "$PASCAL_NAME" | perl -pe 's/(\B[A-Z])/ $1/g') 39 | TITLE_OLD_NAME=$(echo "$PASCAL_OLD_NAME" | perl -pe 's/(\B[A-Z])/ $1/g') 40 | 41 | # Update the program name on the Kinobi config 42 | find $ROOT_DIR/configs/kinobi.cjs -type f -print0 | xargs -0 perl -pi -e "s/$CAMEL_OLD_NAME/$CAMEL_NAME/g" 43 | 44 | # Find and replace 45 | find $ROOT_DIR \ 46 | \( -type d -name .git -prune \) -o \ 47 | \( -type d -name node_modules -prune \) -o \ 48 | \( -type d -name dist -prune \) -o \ 49 | \( -type d -name .crates -prune \) -o \ 50 | \( -type d -name target -prune \) -o \ 51 | ! -name '*.sh' \ 52 | -type f -print0 | 53 | xargs -0 perl -pi -e "s/$OLD_NAME/$NAME/g; \ 54 | s/$SNAKE_OLD_NAME/$SNAKE_NAME/g; \ 55 | s/$CAPITALIZED_SNAKE_OLD_NAME/$CAPITALIZED_SNAKE_NAME/g; \ 56 | s/$CAMEL_OLD_NAME/$CAMEL_NAME/g; \ 57 | s/$PASCAL_OLD_NAME/$PASCAL_NAME/g; \ 58 | s/$TITLE_OLD_NAME/$TITLE_NAME/g; \ 59 | s/$OLD_DESCRIPTION/$DESCRIPTION/g; \ 60 | s/$OLD_PUBLIC_KEY/$PUBLIC_KEY/g" 61 | 62 | # Update folder and file names 63 | mv "$ROOT_DIR/programs/$OLD_NAME" "$ROOT_DIR/programs/$NAME" 64 | mv "$ROOT_DIR/idls/${SNAKE_OLD_NAME}_program.json" "$ROOT_DIR/idls/${SNAKE_NAME}_program.json" 65 | mv "$ROOT_DIR/clients/js/src/generated/errors/$CAMEL_OLD_NAME.ts" "$ROOT_DIR/clients/js/src/generated/errors/$CAMEL_NAME.ts" 66 | mv "$ROOT_DIR/clients/js/src/generated/programs/$CAMEL_OLD_NAME.ts" "$ROOT_DIR/clients/js/src/generated/programs/$CAMEL_NAME.ts" 67 | mv "$ROOT_DIR/clients/rust/src/generated/errors/$SNAKE_OLD_NAME.rs" "$ROOT_DIR/clients/rust/src/generated/errors/$SNAKE_NAME.rs" 68 | 69 | # Update README 70 | rm "$ROOT_DIR/README.md" 71 | mv "$ROOT_DIR/PROJECT_README.md" "$ROOT_DIR/README.md" 72 | 73 | echo "You're all set, build something cool! ✨" 74 | echo "This script will now self-destruct." 75 | 76 | # Self-destruct 77 | rm "$ROOT_DIR/init.sh" 78 | -------------------------------------------------------------------------------- /clients/js/src/generated/shared/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This code was AUTOGENERATED using the kinobi library. 3 | * Please DO NOT EDIT THIS FILE, instead use visitors 4 | * to add features, then rerun kinobi to update it. 5 | * 6 | * @see https://github.com/metaplex-foundation/kinobi 7 | */ 8 | 9 | import { 10 | AccountMeta, 11 | isSigner, 12 | Pda, 13 | publicKey, 14 | PublicKey, 15 | Signer, 16 | isPda, 17 | } from '@metaplex-foundation/umi'; 18 | 19 | /** 20 | * Transforms the given object such that the given keys are optional. 21 | * @internal 22 | */ 23 | export type PickPartial = Omit & 24 | Partial>; 25 | 26 | /** 27 | * Asserts that the given value is not null or undefined. 28 | * @internal 29 | */ 30 | export function expectSome(value: T | null | undefined): T { 31 | if (value == null) { 32 | throw new Error('Expected a value but received null or undefined.'); 33 | } 34 | return value; 35 | } 36 | 37 | /** 38 | * Asserts that the given value is a PublicKey. 39 | * @internal 40 | */ 41 | export function expectPublicKey( 42 | value: PublicKey | Pda | Signer | null | undefined 43 | ): PublicKey { 44 | if (!value) { 45 | throw new Error('Expected a PublicKey.'); 46 | } 47 | return publicKey(value, false); 48 | } 49 | 50 | /** 51 | * Asserts that the given value is a PDA. 52 | * @internal 53 | */ 54 | export function expectPda( 55 | value: PublicKey | Pda | Signer | null | undefined 56 | ): Pda { 57 | if (!value || !Array.isArray(value) || !isPda(value)) { 58 | throw new Error('Expected a PDA.'); 59 | } 60 | return value; 61 | } 62 | 63 | /** 64 | * Defines an instruction account to resolve. 65 | * @internal 66 | */ 67 | export type ResolvedAccount = { 68 | isWritable: boolean; 69 | value: T; 70 | }; 71 | 72 | /** 73 | * Defines a set of instruction account to resolve. 74 | * @internal 75 | */ 76 | export type ResolvedAccounts = Record; 77 | 78 | /** 79 | * Defines a set of instruction account to resolve with their indices. 80 | * @internal 81 | */ 82 | export type ResolvedAccountsWithIndices = Record< 83 | string, 84 | ResolvedAccount & { index: number } 85 | >; 86 | 87 | /** 88 | * Get account metas and signers from resolved accounts. 89 | * @internal 90 | */ 91 | export function getAccountMetasAndSigners( 92 | accounts: ResolvedAccount[], 93 | optionalAccountStrategy: 'omitted' | 'programId', 94 | programId: PublicKey 95 | ): [AccountMeta[], Signer[]] { 96 | const keys: AccountMeta[] = []; 97 | const signers: Signer[] = []; 98 | 99 | accounts.forEach((account) => { 100 | if (!account.value) { 101 | if (optionalAccountStrategy === 'omitted') return; 102 | keys.push({ pubkey: programId, isSigner: false, isWritable: false }); 103 | return; 104 | } 105 | 106 | if (isSigner(account.value)) { 107 | signers.push(account.value); 108 | } 109 | keys.push({ 110 | pubkey: publicKey(account.value, false), 111 | isSigner: isSigner(account.value), 112 | isWritable: account.isWritable, 113 | }); 114 | }); 115 | 116 | return [keys, signers]; 117 | } 118 | -------------------------------------------------------------------------------- /.github/workflows/publish-rust-client.yml: -------------------------------------------------------------------------------- 1 | name: Publish Rust Client 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | level: 7 | description: Level 8 | required: true 9 | default: patch 10 | type: choice 11 | options: 12 | - patch 13 | - minor 14 | - major 15 | - rc 16 | - beta 17 | - alpha 18 | - release 19 | - version 20 | version: 21 | description: Version 22 | required: false 23 | type: string 24 | dry_run: 25 | description: Dry run 26 | required: true 27 | default: true 28 | type: boolean 29 | 30 | env: 31 | CACHE: true 32 | 33 | jobs: 34 | build_programs: 35 | name: Programs 36 | uses: ./.github/workflows/build-programs.yml 37 | secrets: inherit 38 | 39 | build_rust_client: 40 | name: Rust Client 41 | uses: ./.github/workflows/build-rust-client.yml 42 | secrets: inherit 43 | 44 | test_rust_client: 45 | name: Rust Client 46 | needs: [build_programs, build_rust_client] 47 | uses: ./.github/workflows/test-rust-client.yml 48 | secrets: inherit 49 | 50 | publish_crate: 51 | name: Rust Client / Publish Crate 52 | runs-on: ubuntu-latest 53 | needs: test_rust_client 54 | permissions: 55 | contents: write 56 | steps: 57 | - name: Git checkout 58 | uses: actions/checkout@v3 59 | 60 | - name: Load environment variables 61 | run: cat .github/.env >> $GITHUB_ENV 62 | 63 | - name: Install Rust 64 | uses: metaplex-foundation/actions/install-rust@v1 65 | with: 66 | toolchain: ${{ env.RUST_VERSION }} 67 | 68 | - name: Install cargo-release 69 | uses: metaplex-foundation/actions/install-cargo-release@v1 70 | with: 71 | cache: ${{ env.CACHE }} 72 | 73 | - name: Publish crate 74 | working-directory: ./clients/rust 75 | run: | 76 | if [ "${{ inputs.level }}" == "version" ]; then 77 | BUMP=${{ inputs.version }} 78 | else 79 | BUMP=${{ inputs.level }} 80 | fi 81 | 82 | if [ "${{ inputs.dry_run }}" == "false" ]; then 83 | OPTIONS="--no-push --no-tag --no-confirm --execute" 84 | git config user.name ${{ env.COMMIT_USER_NAME }} 85 | git config user.email ${{ env.COMMIT_USER_EMAIL }} 86 | fi 87 | 88 | cargo login ${{ secrets.CRATES_TOKEN }} 89 | cargo release $BUMP $OPTIONS 90 | 91 | if [ "${{ inputs.dry_run }}" == "false" ]; then 92 | git reset --soft HEAD~1 93 | fi 94 | 95 | CLIENT_NAME=`grep -E '^name\s*=' Cargo.toml | awk -F '"' '{print $2}'` 96 | CLIENT_VERSION=`grep -E '^version\s*=' Cargo.toml | awk -F '"' '{print $2}'` 97 | echo CLIENT_NAME="${CLIENT_NAME}" >> $GITHUB_ENV 98 | echo CLIENT_VERSION="${CLIENT_VERSION}" >> $GITHUB_ENV 99 | 100 | - name: Commit and tag new version 101 | uses: stefanzweifel/git-auto-commit-action@v4 102 | if: github.event.inputs.dry_run == 'false' 103 | with: 104 | commit_message: "chore: Release ${{ env.CLIENT_NAME }} version ${{ env.CLIENT_VERSION }}" 105 | tagging_message: ${{ env.CLIENT_NAME }}@v${{ env.CLIENT_VERSION }} 106 | -------------------------------------------------------------------------------- /idls/mpl_project_name_program.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.1.0", 3 | "name": "mpl_project_name_program", 4 | "instructions": [ 5 | { 6 | "name": "Create", 7 | "accounts": [ 8 | { 9 | "name": "address", 10 | "isMut": true, 11 | "isSigner": true, 12 | "docs": [ 13 | "The address of the new account" 14 | ] 15 | }, 16 | { 17 | "name": "authority", 18 | "isMut": false, 19 | "isSigner": false, 20 | "docs": [ 21 | "The authority of the new account" 22 | ] 23 | }, 24 | { 25 | "name": "payer", 26 | "isMut": true, 27 | "isSigner": true, 28 | "docs": [ 29 | "The account paying for the storage fees" 30 | ] 31 | }, 32 | { 33 | "name": "systemProgram", 34 | "isMut": false, 35 | "isSigner": false, 36 | "docs": [ 37 | "The system program" 38 | ] 39 | } 40 | ], 41 | "args": [ 42 | { 43 | "name": "createArgs", 44 | "type": { 45 | "defined": "CreateArgs" 46 | } 47 | } 48 | ], 49 | "discriminant": { 50 | "type": "u8", 51 | "value": 0 52 | } 53 | } 54 | ], 55 | "accounts": [ 56 | { 57 | "name": "MyAccount", 58 | "type": { 59 | "kind": "struct", 60 | "fields": [ 61 | { 62 | "name": "key", 63 | "type": { 64 | "defined": "Key" 65 | } 66 | }, 67 | { 68 | "name": "authority", 69 | "type": "publicKey" 70 | }, 71 | { 72 | "name": "data", 73 | "type": { 74 | "defined": "MyData" 75 | } 76 | } 77 | ] 78 | } 79 | }, 80 | { 81 | "name": "MyPdaAccount", 82 | "type": { 83 | "kind": "struct", 84 | "fields": [ 85 | { 86 | "name": "key", 87 | "type": { 88 | "defined": "Key" 89 | } 90 | }, 91 | { 92 | "name": "bump", 93 | "type": "u8" 94 | } 95 | ] 96 | } 97 | } 98 | ], 99 | "types": [ 100 | { 101 | "name": "CreateArgs", 102 | "type": { 103 | "kind": "struct", 104 | "fields": [ 105 | { 106 | "name": "arg1", 107 | "type": "u16" 108 | }, 109 | { 110 | "name": "arg2", 111 | "type": "u32" 112 | } 113 | ] 114 | } 115 | }, 116 | { 117 | "name": "MyData", 118 | "type": { 119 | "kind": "struct", 120 | "fields": [ 121 | { 122 | "name": "field1", 123 | "type": "u16" 124 | }, 125 | { 126 | "name": "field2", 127 | "type": "u32" 128 | } 129 | ] 130 | } 131 | }, 132 | { 133 | "name": "Key", 134 | "type": { 135 | "kind": "enum", 136 | "variants": [ 137 | { 138 | "name": "Uninitialized" 139 | }, 140 | { 141 | "name": "MyAccount" 142 | }, 143 | { 144 | "name": "MyPdaAccount" 145 | } 146 | ] 147 | } 148 | } 149 | ], 150 | "errors": [ 151 | { 152 | "code": 0, 153 | "name": "InvalidSystemProgram", 154 | "msg": "Invalid System Program" 155 | }, 156 | { 157 | "code": 1, 158 | "name": "DeserializationError", 159 | "msg": "Error deserializing account" 160 | }, 161 | { 162 | "code": 2, 163 | "name": "SerializationError", 164 | "msg": "Error serializing account" 165 | } 166 | ], 167 | "metadata": { 168 | "origin": "shank", 169 | "address": "MyProgram1111111111111111111111111111111111", 170 | "binaryVersion": "0.3.0", 171 | "libVersion": "0.3.0" 172 | } 173 | } -------------------------------------------------------------------------------- /.github/workflows/publish-js-client.yml: -------------------------------------------------------------------------------- 1 | name: Publish JS Client 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | bump: 7 | description: Version bump 8 | required: true 9 | default: patch 10 | type: choice 11 | options: 12 | - patch 13 | - minor 14 | - major 15 | - prerelease 16 | - prepatch 17 | - preminor 18 | - premajor 19 | tag: 20 | description: NPM Tag (and preid for pre-releases) 21 | required: true 22 | type: string 23 | default: latest 24 | create_release: 25 | description: Create a GitHub release 26 | required: true 27 | type: boolean 28 | default: true 29 | 30 | env: 31 | CACHE: true 32 | 33 | jobs: 34 | build_programs: 35 | name: Programs 36 | uses: ./.github/workflows/build-programs.yml 37 | secrets: inherit 38 | 39 | test_js: 40 | name: JS client 41 | needs: build_programs 42 | uses: ./.github/workflows/test-js-client.yml 43 | secrets: inherit 44 | 45 | publish_js: 46 | name: JS client / Publish 47 | runs-on: ubuntu-latest 48 | needs: test_js 49 | permissions: 50 | contents: write 51 | steps: 52 | - name: Git checkout 53 | uses: actions/checkout@v3 54 | 55 | - name: Load environment variables 56 | run: cat .github/.env >> $GITHUB_ENV 57 | 58 | - name: Install Node.js 59 | uses: metaplex-foundation/actions/install-node-with-pnpm@v1 60 | with: 61 | version: ${{ env.NODE_VERSION }} 62 | cache: ${{ env.CACHE }} 63 | 64 | - name: Install dependencies 65 | uses: metaplex-foundation/actions/install-node-dependencies@v1 66 | with: 67 | folder: ./clients/js 68 | cache: ${{ env.CACHE }} 69 | key: clients-js 70 | 71 | - name: Build 72 | working-directory: ./clients/js 73 | run: pnpm build 74 | 75 | - name: Bump 76 | id: bump 77 | working-directory: ./clients/js 78 | run: | 79 | if [ "${{ startsWith(inputs.bump, 'pre') }}" == "true" ]; then 80 | pnpm version ${{ inputs.bump }} --preid ${{ inputs.tag }} --no-git-tag-version 81 | else 82 | pnpm version ${{ inputs.bump }} --no-git-tag-version 83 | fi 84 | echo "new_version=$(pnpm pkg get version | sed 's/"//g')" >> $GITHUB_OUTPUT 85 | 86 | - name: Set publishing config 87 | run: pnpm config set '//registry.npmjs.org/:_authToken' "${NODE_AUTH_TOKEN}" 88 | env: 89 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 90 | 91 | - name: Publish 92 | working-directory: ./clients/js 93 | run: pnpm publish --no-git-checks --tag ${{ inputs.tag }} 94 | 95 | - name: Commit and tag new version 96 | uses: stefanzweifel/git-auto-commit-action@v4 97 | with: 98 | commit_message: Deploy JS client v${{ steps.bump.outputs.new_version }} 99 | tagging_message: js@v${{ steps.bump.outputs.new_version }} 100 | 101 | - name: Create GitHub release 102 | if: github.event.inputs.create_release == 'true' 103 | uses: ncipollo/release-action@v1 104 | with: 105 | tag: js@v${{ steps.bump.outputs.new_version }} 106 | 107 | deploy_js_docs: 108 | name: JS client / Deploy docs 109 | runs-on: ubuntu-latest 110 | needs: publish_js 111 | environment: 112 | name: js-client-documentation 113 | url: ${{ steps.deploy.outputs.url }} 114 | steps: 115 | - name: Git checkout 116 | uses: actions/checkout@v3 117 | with: 118 | ref: ${{ github.ref }} 119 | 120 | - name: Load environment variables 121 | run: cat .github/.env >> $GITHUB_ENV 122 | 123 | - name: Deploy to Vercel 124 | id: deploy 125 | env: 126 | VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} 127 | VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} 128 | working-directory: ./clients/js 129 | run: echo "url=$(vercel deploy --prod --token=${{ secrets.VERCEL_TOKEN }})" | tee $GITHUB_OUTPUT 130 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Main 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | 9 | env: 10 | CACHE: true 11 | 12 | jobs: 13 | changes: 14 | name: Detect changes 15 | runs-on: ubuntu-latest 16 | outputs: 17 | any: ${{ steps.changes.outputs.any }} 18 | programs: ${{ steps.changes.outputs.programs }} 19 | program_matrix: ${{ steps.program_matrix.outputs.matrix }} 20 | js_client: ${{ steps.changes.outputs.js_client }} 21 | rust_client: ${{ steps.changes.outputs.rust_client }} 22 | steps: 23 | - name: Git checkout 24 | uses: actions/checkout@v3 25 | 26 | - name: Load environment variables 27 | run: cat .github/.env >> $GITHUB_ENV 28 | 29 | - name: Detect changes 30 | uses: dorny/paths-filter@v2 31 | id: changes 32 | with: 33 | filters: .github/file-filters.yml 34 | 35 | - name: Filter program matrix 36 | id: program_matrix 37 | uses: metaplex-foundation/actions/filter-matrix@v1 38 | with: 39 | matrix: ${{ env.PROGRAMS }} 40 | changes: ${{ steps.changes.outputs.changes }} 41 | suffix: _program 42 | 43 | build_programs: 44 | name: Programs 45 | if: ${{ needs.changes.outputs.any == 'true' }} 46 | needs: changes 47 | uses: ./.github/workflows/build-programs.yml 48 | secrets: inherit 49 | 50 | test_programs: 51 | name: Programs 52 | if: ${{ needs.changes.outputs.programs == 'true' }} 53 | needs: changes 54 | uses: ./.github/workflows/test-programs.yml 55 | secrets: inherit 56 | with: 57 | program_matrix: ${{ needs.changes.outputs.program_matrix }} 58 | 59 | generate_clients: 60 | name: Generate clients 61 | if: ${{ needs.changes.outputs.any == 'true' }} 62 | needs: build_programs 63 | runs-on: ubuntu-latest 64 | steps: 65 | - name: Git checkout 66 | uses: actions/checkout@v3 67 | 68 | - name: Load environment variables 69 | run: cat .github/.env >> $GITHUB_ENV 70 | 71 | - name: Install Linux Build Deps 72 | run: sudo apt-get update && sudo apt-get install -y pkg-config build-essential libudev-dev 73 | 74 | - name: Install Rust 75 | uses: metaplex-foundation/actions/install-rust@v1 76 | with: 77 | toolchain: ${{ env.RUST_VERSION }} 78 | 79 | - name: Install Solana 80 | uses: metaplex-foundation/actions/install-solana@v1 81 | with: 82 | version: ${{ env.SOLANA_VERSION }} 83 | cache: ${{ env.CACHE }} 84 | 85 | - name: Cache program dependencies 86 | if: env.CACHE == 'true' 87 | uses: metaplex-foundation/actions/cache-programs@v1 88 | 89 | - name: Install Node.js 90 | uses: metaplex-foundation/actions/install-node-with-pnpm@v1 91 | with: 92 | version: ${{ env.NODE_VERSION }} 93 | cache: ${{ env.CACHE }} 94 | dependencies: true 95 | 96 | - name: Cache IDL generators 97 | if: env.CACHE == 'true' 98 | uses: metaplex-foundation/actions/cache-idl-generators@v1 99 | 100 | - name: Generate IDLs and clients 101 | run: pnpm generate 102 | 103 | - name: Ensure working directory is clean 104 | run: test -z "$(git status --porcelain)" 105 | 106 | test_js: 107 | if: needs.changes.outputs.js_client == 'true' 108 | name: JS Client 109 | needs: generate_clients 110 | uses: ./.github/workflows/test-js-client.yml 111 | secrets: inherit 112 | 113 | benchmark: 114 | if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} 115 | name: Benchmark 116 | needs: generate_clients 117 | uses: ./.github/workflows/benchmark.yml 118 | secrets: inherit 119 | 120 | build_rust_client: 121 | if: needs.changes.outputs.rust_client == 'true' 122 | name: Rust Client 123 | needs: generate_clients 124 | uses: ./.github/workflows/build-rust-client.yml 125 | secrets: inherit 126 | 127 | test_rust_client: 128 | if: needs.changes.outputs.rust_client == 'true' 129 | name: Rust Client 130 | needs: generate_clients 131 | uses: ./.github/workflows/test-rust-client.yml 132 | secrets: inherit 133 | -------------------------------------------------------------------------------- /clients/js/src/generated/instructions/create.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This code was AUTOGENERATED using the kinobi library. 3 | * Please DO NOT EDIT THIS FILE, instead use visitors 4 | * to add features, then rerun kinobi to update it. 5 | * 6 | * @see https://github.com/metaplex-foundation/kinobi 7 | */ 8 | 9 | import { 10 | ACCOUNT_HEADER_SIZE, 11 | Context, 12 | Pda, 13 | PublicKey, 14 | Signer, 15 | TransactionBuilder, 16 | transactionBuilder, 17 | } from '@metaplex-foundation/umi'; 18 | import { 19 | Serializer, 20 | mapSerializer, 21 | struct, 22 | u16, 23 | u32, 24 | u8, 25 | } from '@metaplex-foundation/umi/serializers'; 26 | import { getMyAccountSize } from '../accounts'; 27 | import { 28 | ResolvedAccount, 29 | ResolvedAccountsWithIndices, 30 | getAccountMetasAndSigners, 31 | } from '../shared'; 32 | 33 | // Accounts. 34 | export type CreateInstructionAccounts = { 35 | /** The address of the new account */ 36 | address: Signer; 37 | /** The authority of the new account */ 38 | authority?: PublicKey | Pda; 39 | /** The account paying for the storage fees */ 40 | payer?: Signer; 41 | /** The system program */ 42 | systemProgram?: PublicKey | Pda; 43 | }; 44 | 45 | // Data. 46 | export type CreateInstructionData = { 47 | discriminator: number; 48 | arg1: number; 49 | arg2: number; 50 | }; 51 | 52 | export type CreateInstructionDataArgs = { arg1: number; arg2: number }; 53 | 54 | export function getCreateInstructionDataSerializer(): Serializer< 55 | CreateInstructionDataArgs, 56 | CreateInstructionData 57 | > { 58 | return mapSerializer( 59 | struct( 60 | [ 61 | ['discriminator', u8()], 62 | ['arg1', u16()], 63 | ['arg2', u32()], 64 | ], 65 | { description: 'CreateInstructionData' } 66 | ), 67 | (value) => ({ ...value, discriminator: 0 }) 68 | ) as Serializer; 69 | } 70 | 71 | // Args. 72 | export type CreateInstructionArgs = CreateInstructionDataArgs; 73 | 74 | // Instruction. 75 | export function create( 76 | context: Pick, 77 | input: CreateInstructionAccounts & CreateInstructionArgs 78 | ): TransactionBuilder { 79 | // Program ID. 80 | const programId = context.programs.getPublicKey( 81 | 'mplProjectName', 82 | 'MyProgram1111111111111111111111111111111111' 83 | ); 84 | 85 | // Accounts. 86 | const resolvedAccounts = { 87 | address: { 88 | index: 0, 89 | isWritable: true as boolean, 90 | value: input.address ?? null, 91 | }, 92 | authority: { 93 | index: 1, 94 | isWritable: false as boolean, 95 | value: input.authority ?? null, 96 | }, 97 | payer: { 98 | index: 2, 99 | isWritable: true as boolean, 100 | value: input.payer ?? null, 101 | }, 102 | systemProgram: { 103 | index: 3, 104 | isWritable: false as boolean, 105 | value: input.systemProgram ?? null, 106 | }, 107 | } satisfies ResolvedAccountsWithIndices; 108 | 109 | // Arguments. 110 | const resolvedArgs: CreateInstructionArgs = { ...input }; 111 | 112 | // Default values. 113 | if (!resolvedAccounts.authority.value) { 114 | resolvedAccounts.authority.value = context.identity.publicKey; 115 | } 116 | if (!resolvedAccounts.payer.value) { 117 | resolvedAccounts.payer.value = context.payer; 118 | } 119 | if (!resolvedAccounts.systemProgram.value) { 120 | resolvedAccounts.systemProgram.value = context.programs.getPublicKey( 121 | 'splSystem', 122 | '11111111111111111111111111111111' 123 | ); 124 | resolvedAccounts.systemProgram.isWritable = false; 125 | } 126 | 127 | // Accounts in order. 128 | const orderedAccounts: ResolvedAccount[] = Object.values( 129 | resolvedAccounts 130 | ).sort((a, b) => a.index - b.index); 131 | 132 | // Keys and Signers. 133 | const [keys, signers] = getAccountMetasAndSigners( 134 | orderedAccounts, 135 | 'programId', 136 | programId 137 | ); 138 | 139 | // Data. 140 | const data = getCreateInstructionDataSerializer().serialize( 141 | resolvedArgs as CreateInstructionDataArgs 142 | ); 143 | 144 | // Bytes Created On Chain. 145 | const bytesCreatedOnChain = getMyAccountSize() + ACCOUNT_HEADER_SIZE; 146 | 147 | return transactionBuilder([ 148 | { instruction: { keys, programId, data }, signers, bytesCreatedOnChain }, 149 | ]); 150 | } 151 | -------------------------------------------------------------------------------- /clients/js/src/generated/accounts/myAccount.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This code was AUTOGENERATED using the kinobi library. 3 | * Please DO NOT EDIT THIS FILE, instead use visitors 4 | * to add features, then rerun kinobi to update it. 5 | * 6 | * @see https://github.com/metaplex-foundation/kinobi 7 | */ 8 | 9 | import { 10 | Account, 11 | Context, 12 | Pda, 13 | PublicKey, 14 | RpcAccount, 15 | RpcGetAccountOptions, 16 | RpcGetAccountsOptions, 17 | assertAccountExists, 18 | deserializeAccount, 19 | gpaBuilder, 20 | publicKey as toPublicKey, 21 | } from '@metaplex-foundation/umi'; 22 | import { 23 | Serializer, 24 | mapSerializer, 25 | publicKey as publicKeySerializer, 26 | struct, 27 | } from '@metaplex-foundation/umi/serializers'; 28 | import { 29 | Key, 30 | KeyArgs, 31 | MyData, 32 | MyDataArgs, 33 | getKeySerializer, 34 | getMyDataSerializer, 35 | } from '../types'; 36 | 37 | export type MyAccount = Account; 38 | 39 | export type MyAccountAccountData = { 40 | key: Key; 41 | authority: PublicKey; 42 | data: MyData; 43 | }; 44 | 45 | export type MyAccountAccountDataArgs = { 46 | authority: PublicKey; 47 | data: MyDataArgs; 48 | }; 49 | 50 | export function getMyAccountAccountDataSerializer(): Serializer< 51 | MyAccountAccountDataArgs, 52 | MyAccountAccountData 53 | > { 54 | return mapSerializer( 55 | struct( 56 | [ 57 | ['key', getKeySerializer()], 58 | ['authority', publicKeySerializer()], 59 | ['data', getMyDataSerializer()], 60 | ], 61 | { description: 'MyAccountAccountData' } 62 | ), 63 | (value) => ({ ...value, key: Key.MyAccount }) 64 | ) as Serializer; 65 | } 66 | 67 | export function deserializeMyAccount(rawAccount: RpcAccount): MyAccount { 68 | return deserializeAccount(rawAccount, getMyAccountAccountDataSerializer()); 69 | } 70 | 71 | export async function fetchMyAccount( 72 | context: Pick, 73 | publicKey: PublicKey | Pda, 74 | options?: RpcGetAccountOptions 75 | ): Promise { 76 | const maybeAccount = await context.rpc.getAccount( 77 | toPublicKey(publicKey, false), 78 | options 79 | ); 80 | assertAccountExists(maybeAccount, 'MyAccount'); 81 | return deserializeMyAccount(maybeAccount); 82 | } 83 | 84 | export async function safeFetchMyAccount( 85 | context: Pick, 86 | publicKey: PublicKey | Pda, 87 | options?: RpcGetAccountOptions 88 | ): Promise { 89 | const maybeAccount = await context.rpc.getAccount( 90 | toPublicKey(publicKey, false), 91 | options 92 | ); 93 | return maybeAccount.exists ? deserializeMyAccount(maybeAccount) : null; 94 | } 95 | 96 | export async function fetchAllMyAccount( 97 | context: Pick, 98 | publicKeys: Array, 99 | options?: RpcGetAccountsOptions 100 | ): Promise { 101 | const maybeAccounts = await context.rpc.getAccounts( 102 | publicKeys.map((key) => toPublicKey(key, false)), 103 | options 104 | ); 105 | return maybeAccounts.map((maybeAccount) => { 106 | assertAccountExists(maybeAccount, 'MyAccount'); 107 | return deserializeMyAccount(maybeAccount); 108 | }); 109 | } 110 | 111 | export async function safeFetchAllMyAccount( 112 | context: Pick, 113 | publicKeys: Array, 114 | options?: RpcGetAccountsOptions 115 | ): Promise { 116 | const maybeAccounts = await context.rpc.getAccounts( 117 | publicKeys.map((key) => toPublicKey(key, false)), 118 | options 119 | ); 120 | return maybeAccounts 121 | .filter((maybeAccount) => maybeAccount.exists) 122 | .map((maybeAccount) => deserializeMyAccount(maybeAccount as RpcAccount)); 123 | } 124 | 125 | export function getMyAccountGpaBuilder( 126 | context: Pick 127 | ) { 128 | const programId = context.programs.getPublicKey( 129 | 'mplProjectName', 130 | 'MyProgram1111111111111111111111111111111111' 131 | ); 132 | return gpaBuilder(context, programId) 133 | .registerFields<{ key: KeyArgs; authority: PublicKey; data: MyDataArgs }>({ 134 | key: [0, getKeySerializer()], 135 | authority: [1, publicKeySerializer()], 136 | data: [33, getMyDataSerializer()], 137 | }) 138 | .deserializeUsing((account) => deserializeMyAccount(account)) 139 | .whereField('key', Key.MyAccount); 140 | } 141 | 142 | export function getMyAccountSize(): number { 143 | return 39; 144 | } 145 | -------------------------------------------------------------------------------- /clients/js/src/generated/accounts/myPdaAccount.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This code was AUTOGENERATED using the kinobi library. 3 | * Please DO NOT EDIT THIS FILE, instead use visitors 4 | * to add features, then rerun kinobi to update it. 5 | * 6 | * @see https://github.com/metaplex-foundation/kinobi 7 | */ 8 | 9 | import { 10 | Account, 11 | Context, 12 | Pda, 13 | PublicKey, 14 | RpcAccount, 15 | RpcGetAccountOptions, 16 | RpcGetAccountsOptions, 17 | assertAccountExists, 18 | deserializeAccount, 19 | gpaBuilder, 20 | publicKey as toPublicKey, 21 | } from '@metaplex-foundation/umi'; 22 | import { 23 | Serializer, 24 | mapSerializer, 25 | publicKey as publicKeySerializer, 26 | string, 27 | struct, 28 | u8, 29 | } from '@metaplex-foundation/umi/serializers'; 30 | import { Key, KeyArgs, getKeySerializer } from '../types'; 31 | 32 | export type MyPdaAccount = Account; 33 | 34 | export type MyPdaAccountAccountData = { key: Key; bump: number }; 35 | 36 | export type MyPdaAccountAccountDataArgs = { bump: number }; 37 | 38 | export function getMyPdaAccountAccountDataSerializer(): Serializer< 39 | MyPdaAccountAccountDataArgs, 40 | MyPdaAccountAccountData 41 | > { 42 | return mapSerializer< 43 | MyPdaAccountAccountDataArgs, 44 | any, 45 | MyPdaAccountAccountData 46 | >( 47 | struct( 48 | [ 49 | ['key', getKeySerializer()], 50 | ['bump', u8()], 51 | ], 52 | { description: 'MyPdaAccountAccountData' } 53 | ), 54 | (value) => ({ ...value, key: Key.MyPdaAccount }) 55 | ) as Serializer; 56 | } 57 | 58 | export function deserializeMyPdaAccount(rawAccount: RpcAccount): MyPdaAccount { 59 | return deserializeAccount(rawAccount, getMyPdaAccountAccountDataSerializer()); 60 | } 61 | 62 | export async function fetchMyPdaAccount( 63 | context: Pick, 64 | publicKey: PublicKey | Pda, 65 | options?: RpcGetAccountOptions 66 | ): Promise { 67 | const maybeAccount = await context.rpc.getAccount( 68 | toPublicKey(publicKey, false), 69 | options 70 | ); 71 | assertAccountExists(maybeAccount, 'MyPdaAccount'); 72 | return deserializeMyPdaAccount(maybeAccount); 73 | } 74 | 75 | export async function safeFetchMyPdaAccount( 76 | context: Pick, 77 | publicKey: PublicKey | Pda, 78 | options?: RpcGetAccountOptions 79 | ): Promise { 80 | const maybeAccount = await context.rpc.getAccount( 81 | toPublicKey(publicKey, false), 82 | options 83 | ); 84 | return maybeAccount.exists ? deserializeMyPdaAccount(maybeAccount) : null; 85 | } 86 | 87 | export async function fetchAllMyPdaAccount( 88 | context: Pick, 89 | publicKeys: Array, 90 | options?: RpcGetAccountsOptions 91 | ): Promise { 92 | const maybeAccounts = await context.rpc.getAccounts( 93 | publicKeys.map((key) => toPublicKey(key, false)), 94 | options 95 | ); 96 | return maybeAccounts.map((maybeAccount) => { 97 | assertAccountExists(maybeAccount, 'MyPdaAccount'); 98 | return deserializeMyPdaAccount(maybeAccount); 99 | }); 100 | } 101 | 102 | export async function safeFetchAllMyPdaAccount( 103 | context: Pick, 104 | publicKeys: Array, 105 | options?: RpcGetAccountsOptions 106 | ): Promise { 107 | const maybeAccounts = await context.rpc.getAccounts( 108 | publicKeys.map((key) => toPublicKey(key, false)), 109 | options 110 | ); 111 | return maybeAccounts 112 | .filter((maybeAccount) => maybeAccount.exists) 113 | .map((maybeAccount) => deserializeMyPdaAccount(maybeAccount as RpcAccount)); 114 | } 115 | 116 | export function getMyPdaAccountGpaBuilder( 117 | context: Pick 118 | ) { 119 | const programId = context.programs.getPublicKey( 120 | 'mplProjectName', 121 | 'MyProgram1111111111111111111111111111111111' 122 | ); 123 | return gpaBuilder(context, programId) 124 | .registerFields<{ key: KeyArgs; bump: number }>({ 125 | key: [0, getKeySerializer()], 126 | bump: [1, u8()], 127 | }) 128 | .deserializeUsing((account) => 129 | deserializeMyPdaAccount(account) 130 | ) 131 | .whereField('key', Key.MyPdaAccount); 132 | } 133 | 134 | export function getMyPdaAccountSize(): number { 135 | return 2; 136 | } 137 | 138 | export function findMyPdaAccountPda( 139 | context: Pick, 140 | seeds: { 141 | /** The address of the authority */ 142 | authority: PublicKey; 143 | /** The name of the account */ 144 | name: string; 145 | } 146 | ): Pda { 147 | const programId = context.programs.getPublicKey( 148 | 'mplProjectName', 149 | 'MyProgram1111111111111111111111111111111111' 150 | ); 151 | return context.eddsa.findPda(programId, [ 152 | string({ size: 'variable' }).serialize('myPdaAccount'), 153 | publicKeySerializer().serialize(programId), 154 | publicKeySerializer().serialize(seeds.authority), 155 | string().serialize(seeds.name), 156 | ]); 157 | } 158 | 159 | export async function fetchMyPdaAccountFromSeeds( 160 | context: Pick, 161 | seeds: Parameters[1], 162 | options?: RpcGetAccountOptions 163 | ): Promise { 164 | return fetchMyPdaAccount( 165 | context, 166 | findMyPdaAccountPda(context, seeds), 167 | options 168 | ); 169 | } 170 | 171 | export async function safeFetchMyPdaAccountFromSeeds( 172 | context: Pick, 173 | seeds: Parameters[1], 174 | options?: RpcGetAccountOptions 175 | ): Promise { 176 | return safeFetchMyPdaAccount( 177 | context, 178 | findMyPdaAccountPda(context, seeds), 179 | options 180 | ); 181 | } 182 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | METAPLEX(TM) NFT OPEN SOURCE LICENSE 2 | 3 | Version 1.0, Oct. 2022 4 | 5 | PREAMBLE 6 | 7 | As the publisher of the non-fungible token (NFT) standard for the Solana 8 | blockchain, we believe in the set of principles that have guided open source 9 | software development models over the years – Transparency, Collaboration, 10 | Release Early and Often, Community, and Inclusive Meritocracy. Thus, for our 11 | code repository, we have adopted an “Apache-style” licensing scheme. To be 12 | true to our NFT and crypto legacy, however, we do impose some restrictions on 13 | modifying our code that we believe promote the purpose and promise of NFTs in 14 | order to protect the web3 ecosystem. 15 | 16 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 17 | 18 | BY DOWNLOADING, INSTALLING, OR OTHERWISE ACCESSING OR USING THE FILES 19 | ACCOMPANYING THIS LICENSE, YOU AGREE THAT YOU HAVE READ, UNDERSTOOD, AND AGREE 20 | TO BE BOUND BY THIS LICENSE. IF YOU DO NOT AGREE, YOU MAY NOT USE ANY OF THE 21 | ACCOMPANYING FILES. 22 | 23 | 1. Definitions. 24 | 25 | “License” means the terms and conditions for use, reproduction, and 26 | Distribution as defined by Sections 1 through 9 of this document. 27 | 28 | “Licensor” means the copyright owner or entity authorized by the copyright 29 | owner that is granting the License. 30 | 31 | “Legal Entity” means the union of the acting entity and all other entities 32 | that control, are controlled by, or are under common control with that entity. 33 | For the purposes of this definition, “control” means: (i) the power, direct or 34 | indirect, to cause the direction or management of such entity, whether by 35 | contract or otherwise, or (ii) ownership of 50% or more of the outstanding 36 | shares, or (iii) beneficial ownership of such entity. 37 | 38 | “You” (or “Your”) means an individual or Legal Entity exercising permissions 39 | granted by this License. 40 | 41 | “Source Code” means the preferred form for making modifications, including 42 | but not limited to software source code, documentation source, and 43 | configuration files. 44 | 45 | “Object Code” means any form resulting from mechanical transformation or 46 | translation of Source Code, including but not limited to compiled object code, 47 | generated documentation, and conversions to other media types. 48 | 49 | “Work” means the work of authorship, whether in Source Code or Object Code, 50 | made available under the License, as indicated by a copyright notice that is 51 | included in or attached to the work, an example is provided below: 52 | 53 | ------ 54 | Copyright © [yyyy] [name of copyright owner] 55 | Licensed under the Metaplex(TM) NFT Open Source License, Version 1.0 (the 56 | “License”). Use of this file is only permitted when in compliance with the 57 | License. You may obtain a copy of the License at: 58 | https://github.com/metaplex-foundation/ 59 | metaplex-program-library/blob/master/LICENSE 60 | 61 | Unless required by applicable law or agreed to in writing, software 62 | distributed under the License is distributed on an “AS IS” BASIS, WITHOUT 63 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 64 | License for the specific language governing permissions and limitations under 65 | the License. 66 | ------ 67 | 68 | “Derivative Works” means any work, whether in Source Code or Object Code, 69 | that is based on (or derived from) the Work and for which the editorial 70 | revisions, annotations, elaborations, or other modifications represent, as a 71 | whole, an original work of authorship. For the purposes of this License, 72 | Derivative Works shall include works that merely (dynamically or statically) 73 | link or bind by name to the interfaces of the Work and Derivative Works 74 | thereof. 75 | 76 | “Distribution” (or “Distribute”) means to do anything with a work that, 77 | without permission, would make You directly or secondarily liable for 78 | infringement under applicable copyright law, except executing it on a computer 79 | or modifying a private copy, including copying, distribution (with or without 80 | modification), any kind of propagation that enables other parties to make or 81 | receive copies, making it available to the public (either directly or via 82 | remote interaction over a computer network or blockchain), and, in some 83 | countries, other activities as well. 84 | 85 | “Competitive Product” means a Derivative Work that is primarily designed to 86 | function as a commercial substitute for the Work such that the Derivative Work 87 | offers materially similar functionality to a materially similar target 88 | audience as the original Work, including hosting a version of the original 89 | Work that reduces the economic benefit of the original Work to the Licensor. 90 | 91 | “Contribution” means any work of authorship, including the original version 92 | of the Work and any modifications or additions to that Work or Derivative 93 | Works thereof, that is intentionally submitted to Licensor for inclusion in 94 | the Work by the copyright owner or by an individual or Legal Entity authorized 95 | to submit on behalf of the copyright owner. For the purposes of this 96 | definition, “submitted” means any form of electronic, verbal, or written 97 | communication sent to the Licensor or its representatives, including but not 98 | limited to communication on electronic mailing lists, source code control 99 | systems, and issue tracking systems that are managed by, or on behalf of, the 100 | Licensor for the purpose of discussing and improving the Work, but excluding 101 | communication that is conspicuously marked or otherwise designated in writing 102 | by the copyright owner as “Not a Contribution”. 103 | 104 | “Contributor” means Licensor and any individual or Legal Entity on behalf of 105 | whom a Contribution has been received by Licensor and subsequently 106 | incorporated within the Work. 107 | 108 | 109 | 2. Grant of Copyright License. 110 | 111 | Subject to the terms and conditions of this License, each Contributor hereby 112 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, 113 | irrevocable copyright license to reproduce, prepare Derivative Works of, 114 | publicly display, transmit, publicly perform, sublicense, and Distribute the 115 | Work and such Derivative Works in Source Code or Object Code form. 116 | 117 | 3. Grant of Patent License. 118 | 119 | Subject to the terms and conditions of this License, each Contributor hereby 120 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, 121 | irrevocable (except as stated in this section) patent license to make, have 122 | made, use, offer to sell, sell, import, and otherwise transfer the Work, where 123 | such license applies only to those patent claims licensable by such 124 | Contributor that are necessarily infringed by their Contribution(s) alone or 125 | by combination of their Contribution(s) with the Work to which such 126 | Contribution(s) was submitted. If You institute patent litigation against any 127 | entity (including a crossclaim or counterclaim in a lawsuit) alleging that the 128 | Work or a Contribution incorporated within the Work constitutes direct or 129 | contributory patent infringement, then any patent licenses granted to You under 130 | this License for that Work shall terminate as of the date such litigation is 131 | filed. 132 | 133 | 134 | 4. Distribution. 135 | 136 | (a) You may reproduce and Distribute copies of the Work or Derivative Works 137 | thereof in any medium, with or without modifications, and in Source Code or 138 | Object Code form, provided that You meet the following conditions: 139 | 140 | i. You must give any other recipients of the Work or Derivative Works a 141 | copy of this License; 142 | 143 | ii. You must cause any modified files to carry prominent notices stating 144 | that You changed the files; 145 | 146 | iii. You must retain, in the Source Code of any Derivative Works that You 147 | Distribute, all copyright, patent, trademark, and attribution notices from 148 | the Source Code of the Work, excluding those notices that do not pertain 149 | to any part of the Derivative Works; and 150 | 151 | iv. If the Work includes a “NOTICE” text file as part of its Distribution, 152 | then any Derivative Works that You Distribute must include a readable copy 153 | of the attribution notices contained within such NOTICE file, excluding 154 | those notices that do not pertain to any part of the Derivative Works, in 155 | at least one of the following places: 156 | 157 | 1. within a NOTICE text file distributed as part of the Derivative Works; 158 | 2. within the Source Code or documentation, if provided along with the 159 | Derivative Works; or 160 | 3. within a display generated by the Derivative Works, if and wherever 161 | such third-party notices normally appear. 162 | 163 | The contents of the NOTICE file are for informational purposes only and do 164 | not modify the License. You may add Your own attribution notices within 165 | Derivative Works that You Distribute, alongside or as an addendum to the 166 | NOTICE text from the Work, provided that such additional attribution 167 | notices cannot be construed as modifying the License. 168 | 169 | (b) You may add Your own copyright statement to Your modifications and may 170 | provide additional or different license terms and conditions for use, 171 | reproduction, or Distribution of Your modifications, or for any such 172 | Derivative Works as a whole, provided Your use, reproduction, and 173 | Distribution of the Work otherwise complies with the conditions stated in 174 | this License. 175 | 176 | (c) Notwithstanding any other section of this License, You may not under any 177 | circumstances make modifications to the Work to use, produce and Distribute 178 | a Derivative Work, in Source Code or Object Code form, that is a Competitive 179 | Product. 180 | 181 | 5. Submission of Contributions. 182 | 183 | Unless You explicitly state otherwise, any Contribution intentionally 184 | submitted for inclusion in the Work by You to the Licensor shall be under the 185 | terms and conditions of this License, without any additional terms or 186 | conditions. Notwithstanding the above, nothing herein shall supersede or 187 | modify the terms of any separate license agreement you may have executed with 188 | Licensor regarding such Contributions. 189 | 190 | 6. Trademarks. 191 | 192 | This License does not grant permission to use the trade names, trademarks, 193 | service marks, or product names of the Licensor, except as required for 194 | reasonable and customary use in describing the origin of the Work and 195 | reproducing the content of the NOTICE file. 196 | 197 | 7. Disclaimer of Warranty. 198 | 199 | Unless required by applicable law or agreed to in writing, Licensor provides 200 | the Work (and each Contributor provides its Contributions) on an “AS IS” 201 | BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 202 | implied, including, without limitation, any warranties or conditions of TITLE, 203 | NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You 204 | are solely responsible for determining the appropriateness of using or 205 | Distributing the Work and assume any risks associated with Your exercise of 206 | permissions under this License. 207 | 208 | 8. Limitation of Liability. 209 | 210 | In no event and under no legal theory, whether in tort (including 211 | negligence), contract, or otherwise, unless required by applicable law (such 212 | as deliberate and grossly negligent acts) or agreed to in writing, shall any 213 | Contributor be liable to You for damages, including any direct, indirect, 214 | special, incidental, or consequential damages of any character arising as a 215 | result of this License or out of the use or inability to use the Work 216 | (including but not limited to damages for loss of goodwill, work stoppage, 217 | computer failure or malfunction, or any and all other commercial damages or 218 | losses), even if such Contributor has been advised of the possibility of such 219 | damages. 220 | 221 | 9. Accepting Warranty or Additional Liability. 222 | 223 | While Distributing the Work or Derivative Works thereof, You may choose to 224 | offer, and charge a fee for, acceptance of support, warranty, indemnity, or 225 | other liability obligations and/or rights consistent with this License. 226 | However, in accepting such obligations, You may act only on Your own behalf 227 | and on Your sole responsibility, not on behalf of any other Contributor, and 228 | only if You agree to indemnify, defend, and hold each Contributor harmless for 229 | any liability incurred by, or claims asserted against, such Contributor by 230 | reason of your accepting any such warranty or additional liability. 231 | 232 | 10. Revised Versions of this License. 233 | 234 | The Metaplex Foundation may publish revised, newer versions of this License 235 | from time to time. Such new versions will be similar in spirit to the present 236 | version but may differ in detail to address new problems or concerns. Each 237 | version will be given a distinguishing version number. If the Work specifies a 238 | certain version of the Metaplex(TM) NFT Open Source License, then that version 239 | shall apply. If the Work does not specify a version number of the Metaplex(TM) 240 | NFT Open Source License, then the latest version published by the Metaplex 241 | Foundation shall apply. 242 | -------------------------------------------------------------------------------- /clients/rust/src/generated/instructions/create.rs: -------------------------------------------------------------------------------- 1 | //! This code was AUTOGENERATED using the kinobi library. 2 | //! Please DO NOT EDIT THIS FILE, instead use visitors 3 | //! to add features, then rerun kinobi to update it. 4 | //! 5 | //! [https://github.com/metaplex-foundation/kinobi] 6 | //! 7 | 8 | use borsh::BorshDeserialize; 9 | use borsh::BorshSerialize; 10 | 11 | /// Accounts. 12 | pub struct Create { 13 | /// The address of the new account 14 | pub address: solana_program::pubkey::Pubkey, 15 | /// The authority of the new account 16 | pub authority: solana_program::pubkey::Pubkey, 17 | /// The account paying for the storage fees 18 | pub payer: solana_program::pubkey::Pubkey, 19 | /// The system program 20 | pub system_program: solana_program::pubkey::Pubkey, 21 | } 22 | 23 | impl Create { 24 | pub fn instruction( 25 | &self, 26 | args: CreateInstructionArgs, 27 | ) -> solana_program::instruction::Instruction { 28 | self.instruction_with_remaining_accounts(args, &[]) 29 | } 30 | #[allow(clippy::vec_init_then_push)] 31 | pub fn instruction_with_remaining_accounts( 32 | &self, 33 | args: CreateInstructionArgs, 34 | remaining_accounts: &[solana_program::instruction::AccountMeta], 35 | ) -> solana_program::instruction::Instruction { 36 | let mut accounts = Vec::with_capacity(4 + remaining_accounts.len()); 37 | accounts.push(solana_program::instruction::AccountMeta::new( 38 | self.address, 39 | true, 40 | )); 41 | accounts.push(solana_program::instruction::AccountMeta::new_readonly( 42 | self.authority, 43 | false, 44 | )); 45 | accounts.push(solana_program::instruction::AccountMeta::new( 46 | self.payer, true, 47 | )); 48 | accounts.push(solana_program::instruction::AccountMeta::new_readonly( 49 | self.system_program, 50 | false, 51 | )); 52 | accounts.extend_from_slice(remaining_accounts); 53 | let mut data = CreateInstructionData::new().try_to_vec().unwrap(); 54 | let mut args = args.try_to_vec().unwrap(); 55 | data.append(&mut args); 56 | 57 | solana_program::instruction::Instruction { 58 | program_id: crate::MPL_PROJECT_NAME_ID, 59 | accounts, 60 | data, 61 | } 62 | } 63 | } 64 | 65 | #[derive(BorshDeserialize, BorshSerialize)] 66 | struct CreateInstructionData { 67 | discriminator: u8, 68 | } 69 | 70 | impl CreateInstructionData { 71 | fn new() -> Self { 72 | Self { discriminator: 0 } 73 | } 74 | } 75 | 76 | #[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] 77 | #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 78 | pub struct CreateInstructionArgs { 79 | pub arg1: u16, 80 | pub arg2: u32, 81 | } 82 | 83 | /// Instruction builder for `Create`. 84 | /// 85 | /// ### Accounts: 86 | /// 87 | /// 0. `[writable, signer]` address 88 | /// 1. `[]` authority 89 | /// 2. `[writable, signer]` payer 90 | /// 3. `[optional]` system_program (default to `11111111111111111111111111111111`) 91 | #[derive(Default)] 92 | pub struct CreateBuilder { 93 | address: Option, 94 | authority: Option, 95 | payer: Option, 96 | system_program: Option, 97 | arg1: Option, 98 | arg2: Option, 99 | __remaining_accounts: Vec, 100 | } 101 | 102 | impl CreateBuilder { 103 | pub fn new() -> Self { 104 | Self::default() 105 | } 106 | /// The address of the new account 107 | #[inline(always)] 108 | pub fn address(&mut self, address: solana_program::pubkey::Pubkey) -> &mut Self { 109 | self.address = Some(address); 110 | self 111 | } 112 | /// The authority of the new account 113 | #[inline(always)] 114 | pub fn authority(&mut self, authority: solana_program::pubkey::Pubkey) -> &mut Self { 115 | self.authority = Some(authority); 116 | self 117 | } 118 | /// The account paying for the storage fees 119 | #[inline(always)] 120 | pub fn payer(&mut self, payer: solana_program::pubkey::Pubkey) -> &mut Self { 121 | self.payer = Some(payer); 122 | self 123 | } 124 | /// `[optional account, default to '11111111111111111111111111111111']` 125 | /// The system program 126 | #[inline(always)] 127 | pub fn system_program(&mut self, system_program: solana_program::pubkey::Pubkey) -> &mut Self { 128 | self.system_program = Some(system_program); 129 | self 130 | } 131 | #[inline(always)] 132 | pub fn arg1(&mut self, arg1: u16) -> &mut Self { 133 | self.arg1 = Some(arg1); 134 | self 135 | } 136 | #[inline(always)] 137 | pub fn arg2(&mut self, arg2: u32) -> &mut Self { 138 | self.arg2 = Some(arg2); 139 | self 140 | } 141 | /// Add an aditional account to the instruction. 142 | #[inline(always)] 143 | pub fn add_remaining_account( 144 | &mut self, 145 | account: solana_program::instruction::AccountMeta, 146 | ) -> &mut Self { 147 | self.__remaining_accounts.push(account); 148 | self 149 | } 150 | /// Add additional accounts to the instruction. 151 | #[inline(always)] 152 | pub fn add_remaining_accounts( 153 | &mut self, 154 | accounts: &[solana_program::instruction::AccountMeta], 155 | ) -> &mut Self { 156 | self.__remaining_accounts.extend_from_slice(accounts); 157 | self 158 | } 159 | #[allow(clippy::clone_on_copy)] 160 | pub fn instruction(&self) -> solana_program::instruction::Instruction { 161 | let accounts = Create { 162 | address: self.address.expect("address is not set"), 163 | authority: self.authority.expect("authority is not set"), 164 | payer: self.payer.expect("payer is not set"), 165 | system_program: self 166 | .system_program 167 | .unwrap_or(solana_program::pubkey!("11111111111111111111111111111111")), 168 | }; 169 | let args = CreateInstructionArgs { 170 | arg1: self.arg1.clone().expect("arg1 is not set"), 171 | arg2: self.arg2.clone().expect("arg2 is not set"), 172 | }; 173 | 174 | accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) 175 | } 176 | } 177 | 178 | /// `create` CPI accounts. 179 | pub struct CreateCpiAccounts<'a, 'b> { 180 | /// The address of the new account 181 | pub address: &'b solana_program::account_info::AccountInfo<'a>, 182 | /// The authority of the new account 183 | pub authority: &'b solana_program::account_info::AccountInfo<'a>, 184 | /// The account paying for the storage fees 185 | pub payer: &'b solana_program::account_info::AccountInfo<'a>, 186 | /// The system program 187 | pub system_program: &'b solana_program::account_info::AccountInfo<'a>, 188 | } 189 | 190 | /// `create` CPI instruction. 191 | pub struct CreateCpi<'a, 'b> { 192 | /// The program to invoke. 193 | pub __program: &'b solana_program::account_info::AccountInfo<'a>, 194 | /// The address of the new account 195 | pub address: &'b solana_program::account_info::AccountInfo<'a>, 196 | /// The authority of the new account 197 | pub authority: &'b solana_program::account_info::AccountInfo<'a>, 198 | /// The account paying for the storage fees 199 | pub payer: &'b solana_program::account_info::AccountInfo<'a>, 200 | /// The system program 201 | pub system_program: &'b solana_program::account_info::AccountInfo<'a>, 202 | /// The arguments for the instruction. 203 | pub __args: CreateInstructionArgs, 204 | } 205 | 206 | impl<'a, 'b> CreateCpi<'a, 'b> { 207 | pub fn new( 208 | program: &'b solana_program::account_info::AccountInfo<'a>, 209 | accounts: CreateCpiAccounts<'a, 'b>, 210 | args: CreateInstructionArgs, 211 | ) -> Self { 212 | Self { 213 | __program: program, 214 | address: accounts.address, 215 | authority: accounts.authority, 216 | payer: accounts.payer, 217 | system_program: accounts.system_program, 218 | __args: args, 219 | } 220 | } 221 | #[inline(always)] 222 | pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { 223 | self.invoke_signed_with_remaining_accounts(&[], &[]) 224 | } 225 | #[inline(always)] 226 | pub fn invoke_with_remaining_accounts( 227 | &self, 228 | remaining_accounts: &[( 229 | &'b solana_program::account_info::AccountInfo<'a>, 230 | bool, 231 | bool, 232 | )], 233 | ) -> solana_program::entrypoint::ProgramResult { 234 | self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) 235 | } 236 | #[inline(always)] 237 | pub fn invoke_signed( 238 | &self, 239 | signers_seeds: &[&[&[u8]]], 240 | ) -> solana_program::entrypoint::ProgramResult { 241 | self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) 242 | } 243 | #[allow(clippy::clone_on_copy)] 244 | #[allow(clippy::vec_init_then_push)] 245 | pub fn invoke_signed_with_remaining_accounts( 246 | &self, 247 | signers_seeds: &[&[&[u8]]], 248 | remaining_accounts: &[( 249 | &'b solana_program::account_info::AccountInfo<'a>, 250 | bool, 251 | bool, 252 | )], 253 | ) -> solana_program::entrypoint::ProgramResult { 254 | let mut accounts = Vec::with_capacity(4 + remaining_accounts.len()); 255 | accounts.push(solana_program::instruction::AccountMeta::new( 256 | *self.address.key, 257 | true, 258 | )); 259 | accounts.push(solana_program::instruction::AccountMeta::new_readonly( 260 | *self.authority.key, 261 | false, 262 | )); 263 | accounts.push(solana_program::instruction::AccountMeta::new( 264 | *self.payer.key, 265 | true, 266 | )); 267 | accounts.push(solana_program::instruction::AccountMeta::new_readonly( 268 | *self.system_program.key, 269 | false, 270 | )); 271 | remaining_accounts.iter().for_each(|remaining_account| { 272 | accounts.push(solana_program::instruction::AccountMeta { 273 | pubkey: *remaining_account.0.key, 274 | is_signer: remaining_account.1, 275 | is_writable: remaining_account.2, 276 | }) 277 | }); 278 | let mut data = CreateInstructionData::new().try_to_vec().unwrap(); 279 | let mut args = self.__args.try_to_vec().unwrap(); 280 | data.append(&mut args); 281 | 282 | let instruction = solana_program::instruction::Instruction { 283 | program_id: crate::MPL_PROJECT_NAME_ID, 284 | accounts, 285 | data, 286 | }; 287 | let mut account_infos = Vec::with_capacity(4 + 1 + remaining_accounts.len()); 288 | account_infos.push(self.__program.clone()); 289 | account_infos.push(self.address.clone()); 290 | account_infos.push(self.authority.clone()); 291 | account_infos.push(self.payer.clone()); 292 | account_infos.push(self.system_program.clone()); 293 | remaining_accounts 294 | .iter() 295 | .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); 296 | 297 | if signers_seeds.is_empty() { 298 | solana_program::program::invoke(&instruction, &account_infos) 299 | } else { 300 | solana_program::program::invoke_signed(&instruction, &account_infos, signers_seeds) 301 | } 302 | } 303 | } 304 | 305 | /// Instruction builder for `Create` via CPI. 306 | /// 307 | /// ### Accounts: 308 | /// 309 | /// 0. `[writable, signer]` address 310 | /// 1. `[]` authority 311 | /// 2. `[writable, signer]` payer 312 | /// 3. `[]` system_program 313 | pub struct CreateCpiBuilder<'a, 'b> { 314 | instruction: Box>, 315 | } 316 | 317 | impl<'a, 'b> CreateCpiBuilder<'a, 'b> { 318 | pub fn new(program: &'b solana_program::account_info::AccountInfo<'a>) -> Self { 319 | let instruction = Box::new(CreateCpiBuilderInstruction { 320 | __program: program, 321 | address: None, 322 | authority: None, 323 | payer: None, 324 | system_program: None, 325 | arg1: None, 326 | arg2: None, 327 | __remaining_accounts: Vec::new(), 328 | }); 329 | Self { instruction } 330 | } 331 | /// The address of the new account 332 | #[inline(always)] 333 | pub fn address( 334 | &mut self, 335 | address: &'b solana_program::account_info::AccountInfo<'a>, 336 | ) -> &mut Self { 337 | self.instruction.address = Some(address); 338 | self 339 | } 340 | /// The authority of the new account 341 | #[inline(always)] 342 | pub fn authority( 343 | &mut self, 344 | authority: &'b solana_program::account_info::AccountInfo<'a>, 345 | ) -> &mut Self { 346 | self.instruction.authority = Some(authority); 347 | self 348 | } 349 | /// The account paying for the storage fees 350 | #[inline(always)] 351 | pub fn payer(&mut self, payer: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { 352 | self.instruction.payer = Some(payer); 353 | self 354 | } 355 | /// The system program 356 | #[inline(always)] 357 | pub fn system_program( 358 | &mut self, 359 | system_program: &'b solana_program::account_info::AccountInfo<'a>, 360 | ) -> &mut Self { 361 | self.instruction.system_program = Some(system_program); 362 | self 363 | } 364 | #[inline(always)] 365 | pub fn arg1(&mut self, arg1: u16) -> &mut Self { 366 | self.instruction.arg1 = Some(arg1); 367 | self 368 | } 369 | #[inline(always)] 370 | pub fn arg2(&mut self, arg2: u32) -> &mut Self { 371 | self.instruction.arg2 = Some(arg2); 372 | self 373 | } 374 | /// Add an additional account to the instruction. 375 | #[inline(always)] 376 | pub fn add_remaining_account( 377 | &mut self, 378 | account: &'b solana_program::account_info::AccountInfo<'a>, 379 | is_writable: bool, 380 | is_signer: bool, 381 | ) -> &mut Self { 382 | self.instruction 383 | .__remaining_accounts 384 | .push((account, is_writable, is_signer)); 385 | self 386 | } 387 | /// Add additional accounts to the instruction. 388 | /// 389 | /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, 390 | /// and a `bool` indicating whether the account is a signer or not. 391 | #[inline(always)] 392 | pub fn add_remaining_accounts( 393 | &mut self, 394 | accounts: &[( 395 | &'b solana_program::account_info::AccountInfo<'a>, 396 | bool, 397 | bool, 398 | )], 399 | ) -> &mut Self { 400 | self.instruction 401 | .__remaining_accounts 402 | .extend_from_slice(accounts); 403 | self 404 | } 405 | #[inline(always)] 406 | pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { 407 | self.invoke_signed(&[]) 408 | } 409 | #[allow(clippy::clone_on_copy)] 410 | #[allow(clippy::vec_init_then_push)] 411 | pub fn invoke_signed( 412 | &self, 413 | signers_seeds: &[&[&[u8]]], 414 | ) -> solana_program::entrypoint::ProgramResult { 415 | let args = CreateInstructionArgs { 416 | arg1: self.instruction.arg1.clone().expect("arg1 is not set"), 417 | arg2: self.instruction.arg2.clone().expect("arg2 is not set"), 418 | }; 419 | let instruction = CreateCpi { 420 | __program: self.instruction.__program, 421 | 422 | address: self.instruction.address.expect("address is not set"), 423 | 424 | authority: self.instruction.authority.expect("authority is not set"), 425 | 426 | payer: self.instruction.payer.expect("payer is not set"), 427 | 428 | system_program: self 429 | .instruction 430 | .system_program 431 | .expect("system_program is not set"), 432 | __args: args, 433 | }; 434 | instruction.invoke_signed_with_remaining_accounts( 435 | signers_seeds, 436 | &self.instruction.__remaining_accounts, 437 | ) 438 | } 439 | } 440 | 441 | struct CreateCpiBuilderInstruction<'a, 'b> { 442 | __program: &'b solana_program::account_info::AccountInfo<'a>, 443 | address: Option<&'b solana_program::account_info::AccountInfo<'a>>, 444 | authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, 445 | payer: Option<&'b solana_program::account_info::AccountInfo<'a>>, 446 | system_program: Option<&'b solana_program::account_info::AccountInfo<'a>>, 447 | arg1: Option, 448 | arg2: Option, 449 | /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. 450 | __remaining_accounts: Vec<( 451 | &'b solana_program::account_info::AccountInfo<'a>, 452 | bool, 453 | bool, 454 | )>, 455 | } 456 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '6.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | devDependencies: 8 | '@metaplex-foundation/amman': 9 | specifier: ^0.12.1 10 | version: 0.12.1(typescript@4.9.5) 11 | '@metaplex-foundation/kinobi': 12 | specifier: ^0.18.4 13 | version: 0.18.4(fastestsmallesttextencoderdecoder@1.0.22) 14 | '@metaplex-foundation/shank-js': 15 | specifier: ^0.1.7 16 | version: 0.1.7 17 | typescript: 18 | specifier: ^4.9.4 19 | version: 4.9.5 20 | 21 | packages: 22 | 23 | /@babel/runtime@7.21.0: 24 | resolution: {integrity: sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==} 25 | engines: {node: '>=6.9.0'} 26 | dependencies: 27 | regenerator-runtime: 0.13.11 28 | dev: true 29 | 30 | /@hapi/hoek@9.3.0: 31 | resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==} 32 | dev: true 33 | 34 | /@hapi/topo@5.1.0: 35 | resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==} 36 | dependencies: 37 | '@hapi/hoek': 9.3.0 38 | dev: true 39 | 40 | /@metaplex-foundation/amman-client@0.2.4: 41 | resolution: {integrity: sha512-AB2zKDrGyJtQqUmOswsZCflIuldYmsPvL/zIU/66JOD9HDo8yyz5ITCrs+/0QoW+CIJkotC5JEhuYuBnqLhmNw==} 42 | dependencies: 43 | '@metaplex-foundation/cusper': 0.0.2 44 | '@solana/spl-token-registry': 0.2.4574 45 | '@solana/web3.js': 1.75.0 46 | bn.js: 5.2.1 47 | debug: 4.3.4 48 | js-sha3: 0.8.0 49 | socket.io-client: 4.6.1 50 | tweetnacl: 1.0.3 51 | transitivePeerDependencies: 52 | - bufferutil 53 | - encoding 54 | - supports-color 55 | - utf-8-validate 56 | dev: true 57 | 58 | /@metaplex-foundation/amman@0.12.1(typescript@4.9.5): 59 | resolution: {integrity: sha512-F3cdHr11ByLGMCrSBRvRCf5uIlhLE+5sWaHT2ZzcE6zVyDta3gs/A12ZBzYZS8ugNETNpJySfB42kMp1VZwbUA==} 60 | hasBin: true 61 | dependencies: 62 | '@metaplex-foundation/amman-client': 0.2.4 63 | '@solana/spl-token': 0.2.0 64 | '@solana/web3.js': 1.75.0 65 | ansi-colors: 4.1.3 66 | bn.js: 5.2.1 67 | buffer-hexdump: 1.0.0 68 | date-fns: 2.29.3 69 | debug: 4.3.4 70 | deep-diff: 1.0.2 71 | diff: 5.1.0 72 | numeral: 2.0.6 73 | port-pid: 0.0.7 74 | socket.io: 4.6.1 75 | text-table: 0.2.0 76 | timeago.js: 4.0.2 77 | ts-essentials: 9.3.1(typescript@4.9.5) 78 | wait-on: 6.0.1(debug@4.3.4) 79 | yargs: 17.7.1 80 | transitivePeerDependencies: 81 | - bufferutil 82 | - encoding 83 | - supports-color 84 | - typescript 85 | - utf-8-validate 86 | dev: true 87 | 88 | /@metaplex-foundation/cusper@0.0.2: 89 | resolution: {integrity: sha512-S9RulC2fFCFOQraz61bij+5YCHhSO9llJegK8c8Y6731fSi6snUSQJdCUqYS8AIgR0TKbQvdvgSyIIdbDFZbBA==} 90 | dev: true 91 | 92 | /@metaplex-foundation/kinobi@0.18.4(fastestsmallesttextencoderdecoder@1.0.22): 93 | resolution: {integrity: sha512-at4rR31Rh3guC4YgyrmV31L2OxITaLnx42x7d1O/rFfg7APsFiT6ewgCrkZPRwwdfYMB/ado4lbB0X69uh9lkQ==} 94 | dependencies: 95 | '@noble/hashes': 1.4.0 96 | '@prettier/sync': 0.5.2(prettier@3.2.5) 97 | '@solana/codecs-strings': 2.0.0-preview.1(fastestsmallesttextencoderdecoder@1.0.22) 98 | chalk: 4.1.2 99 | json-stable-stringify: 1.1.1 100 | nunjucks: 3.2.4 101 | prettier: 3.2.5 102 | transitivePeerDependencies: 103 | - chokidar 104 | - fastestsmallesttextencoderdecoder 105 | dev: true 106 | 107 | /@metaplex-foundation/rustbin@0.3.5: 108 | resolution: {integrity: sha512-m0wkRBEQB/8krwMwKBvFugufZtYwMXiGHud2cTDAv+aGXK4M90y0Hx67/wpu+AqqoQfdV8VM9YezUOHKD+Z5kA==} 109 | dependencies: 110 | debug: 4.3.4 111 | semver: 7.5.0 112 | text-table: 0.2.0 113 | toml: 3.0.0 114 | transitivePeerDependencies: 115 | - supports-color 116 | dev: true 117 | 118 | /@metaplex-foundation/shank-js@0.1.7: 119 | resolution: {integrity: sha512-tSAipn8Ho1UxlMC3jwJ5Opl+Y3lRm60VTkgRDfvzydb57lXW5G+K5MrZhEmhrFUuRYziV+e34CTo+ybpMp1Eqg==} 120 | dependencies: 121 | '@metaplex-foundation/rustbin': 0.3.5 122 | ansi-colors: 4.1.3 123 | debug: 4.3.4 124 | transitivePeerDependencies: 125 | - supports-color 126 | dev: true 127 | 128 | /@noble/ed25519@1.7.3: 129 | resolution: {integrity: sha512-iR8GBkDt0Q3GyaVcIu7mSsVIqnFbkbRzGLWlvhwunacoLwt4J3swfKhfaM6rN6WY+TBGoYT1GtT1mIh2/jGbRQ==} 130 | dev: true 131 | 132 | /@noble/hashes@1.3.0: 133 | resolution: {integrity: sha512-ilHEACi9DwqJB0pw7kv+Apvh50jiiSyR/cQ3y4W7lOR5mhvn/50FLUfsnfJz0BDZtl/RR16kXvptiv6q1msYZg==} 134 | dev: true 135 | 136 | /@noble/hashes@1.4.0: 137 | resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} 138 | engines: {node: '>= 16'} 139 | dev: true 140 | 141 | /@noble/secp256k1@1.7.1: 142 | resolution: {integrity: sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==} 143 | dev: true 144 | 145 | /@prettier/sync@0.5.2(prettier@3.2.5): 146 | resolution: {integrity: sha512-Yb569su456XNx5BsH/Vyem7xD6g/y9iLmLUzRKM1a/dhU/D7HqqvkAG72znulXlMXztbV0iiu9O5AL8K98TzZQ==} 147 | peerDependencies: 148 | prettier: '*' 149 | dependencies: 150 | make-synchronized: 0.2.9 151 | prettier: 3.2.5 152 | dev: true 153 | 154 | /@sideway/address@4.1.4: 155 | resolution: {integrity: sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==} 156 | dependencies: 157 | '@hapi/hoek': 9.3.0 158 | dev: true 159 | 160 | /@sideway/formula@3.0.1: 161 | resolution: {integrity: sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==} 162 | dev: true 163 | 164 | /@sideway/pinpoint@2.0.0: 165 | resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==} 166 | dev: true 167 | 168 | /@socket.io/component-emitter@3.1.0: 169 | resolution: {integrity: sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==} 170 | dev: true 171 | 172 | /@solana/buffer-layout-utils@0.2.0: 173 | resolution: {integrity: sha512-szG4sxgJGktbuZYDg2FfNmkMi0DYQoVjN2h7ta1W1hPrwzarcFLBq9UpX1UjNXsNpT9dn+chgprtWGioUAr4/g==} 174 | engines: {node: '>= 10'} 175 | dependencies: 176 | '@solana/buffer-layout': 4.0.1 177 | '@solana/web3.js': 1.75.0 178 | bigint-buffer: 1.1.5 179 | bignumber.js: 9.1.1 180 | transitivePeerDependencies: 181 | - bufferutil 182 | - encoding 183 | - supports-color 184 | - utf-8-validate 185 | dev: true 186 | 187 | /@solana/buffer-layout@4.0.1: 188 | resolution: {integrity: sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA==} 189 | engines: {node: '>=5.10'} 190 | dependencies: 191 | buffer: 6.0.3 192 | dev: true 193 | 194 | /@solana/codecs-core@2.0.0-preview.1: 195 | resolution: {integrity: sha512-0y3kgFSJAOApNGefEOgLRMiXOHVmcF29Xw3zmR4LDUABvytG3ecKMXGz5oLt3vdaU2CyN3tuUVeGmQjrd0U1kw==} 196 | dependencies: 197 | '@solana/errors': 2.0.0-preview.1 198 | dev: true 199 | 200 | /@solana/codecs-numbers@2.0.0-preview.1: 201 | resolution: {integrity: sha512-NFA8itgcYUY3hkWMBpVRozd2poy1zfOvkIWZKx/D69oIMUtQTBpKrodRVBuhlBkAv12vDNkFljqVySpcMZMl7A==} 202 | dependencies: 203 | '@solana/codecs-core': 2.0.0-preview.1 204 | '@solana/errors': 2.0.0-preview.1 205 | dev: true 206 | 207 | /@solana/codecs-strings@2.0.0-preview.1(fastestsmallesttextencoderdecoder@1.0.22): 208 | resolution: {integrity: sha512-kBAxE9ZD5/c8j9CkPxqc55dbo7R50Re3k94SXR+k13DZCCs37Fyn0/mAkw/S95fofbi/zsi4jSfmsT5vCZD75A==} 209 | peerDependencies: 210 | fastestsmallesttextencoderdecoder: ^1.0.22 211 | dependencies: 212 | '@solana/codecs-core': 2.0.0-preview.1 213 | '@solana/codecs-numbers': 2.0.0-preview.1 214 | '@solana/errors': 2.0.0-preview.1 215 | fastestsmallesttextencoderdecoder: 1.0.22 216 | dev: true 217 | 218 | /@solana/errors@2.0.0-preview.1: 219 | resolution: {integrity: sha512-mnBWfLVwMH4hxwb4sWZ7G7djQCMsyymjysvUPDiF89LueTBm1hfdxUv8Cy1uUCGsJ3jO3scdPwB4noOgr0rG/g==} 220 | hasBin: true 221 | dependencies: 222 | chalk: 5.3.0 223 | commander: 12.0.0 224 | dev: true 225 | 226 | /@solana/spl-token-registry@0.2.4574: 227 | resolution: {integrity: sha512-JzlfZmke8Rxug20VT/VpI2XsXlsqMlcORIUivF+Yucj7tFi7A0dXG7h+2UnD0WaZJw8BrUz2ABNkUnv89vbv1A==} 228 | engines: {node: '>=10'} 229 | dependencies: 230 | cross-fetch: 3.0.6 231 | dev: true 232 | 233 | /@solana/spl-token@0.2.0: 234 | resolution: {integrity: sha512-RWcn31OXtdqIxmkzQfB2R+WpsJOVS6rKuvpxJFjvik2LyODd+WN58ZP3Rpjpro03fscGAkzlFuP3r42doRJgyQ==} 235 | engines: {node: '>= 14'} 236 | dependencies: 237 | '@solana/buffer-layout': 4.0.1 238 | '@solana/buffer-layout-utils': 0.2.0 239 | '@solana/web3.js': 1.75.0 240 | start-server-and-test: 1.15.4 241 | transitivePeerDependencies: 242 | - bufferutil 243 | - encoding 244 | - supports-color 245 | - utf-8-validate 246 | dev: true 247 | 248 | /@solana/web3.js@1.75.0: 249 | resolution: {integrity: sha512-rHQgdo1EWfb+nPUpHe4O7i8qJPELHKNR5PAZRK+a7XxiykqOfbaAlPt5boDWAGPnYbSv0ziWZv5mq9DlFaQCxg==} 250 | dependencies: 251 | '@babel/runtime': 7.21.0 252 | '@noble/ed25519': 1.7.3 253 | '@noble/hashes': 1.3.0 254 | '@noble/secp256k1': 1.7.1 255 | '@solana/buffer-layout': 4.0.1 256 | agentkeepalive: 4.3.0 257 | bigint-buffer: 1.1.5 258 | bn.js: 5.2.1 259 | borsh: 0.7.0 260 | bs58: 4.0.1 261 | buffer: 6.0.3 262 | fast-stable-stringify: 1.0.0 263 | jayson: 3.7.0 264 | node-fetch: 2.6.9 265 | rpc-websockets: 7.5.1 266 | superstruct: 0.14.2 267 | transitivePeerDependencies: 268 | - bufferutil 269 | - encoding 270 | - supports-color 271 | - utf-8-validate 272 | dev: true 273 | 274 | /@types/connect@3.4.35: 275 | resolution: {integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==} 276 | dependencies: 277 | '@types/node': 12.20.55 278 | dev: true 279 | 280 | /@types/cookie@0.4.1: 281 | resolution: {integrity: sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==} 282 | dev: true 283 | 284 | /@types/cors@2.8.13: 285 | resolution: {integrity: sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==} 286 | dependencies: 287 | '@types/node': 18.16.1 288 | dev: true 289 | 290 | /@types/node@12.20.55: 291 | resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} 292 | dev: true 293 | 294 | /@types/node@18.16.1: 295 | resolution: {integrity: sha512-DZxSZWXxFfOlx7k7Rv4LAyiMroaxa3Ly/7OOzZO8cBNho0YzAi4qlbrx8W27JGqG57IgR/6J7r+nOJWw6kcvZA==} 296 | dev: true 297 | 298 | /@types/ws@7.4.7: 299 | resolution: {integrity: sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==} 300 | dependencies: 301 | '@types/node': 12.20.55 302 | dev: true 303 | 304 | /JSONStream@1.3.5: 305 | resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} 306 | hasBin: true 307 | dependencies: 308 | jsonparse: 1.3.1 309 | through: 2.3.8 310 | dev: true 311 | 312 | /a-sync-waterfall@1.0.1: 313 | resolution: {integrity: sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA==} 314 | dev: true 315 | 316 | /accepts@1.3.8: 317 | resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} 318 | engines: {node: '>= 0.6'} 319 | dependencies: 320 | mime-types: 2.1.35 321 | negotiator: 0.6.3 322 | dev: true 323 | 324 | /agentkeepalive@4.3.0: 325 | resolution: {integrity: sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg==} 326 | engines: {node: '>= 8.0.0'} 327 | dependencies: 328 | debug: 4.3.4 329 | depd: 2.0.0 330 | humanize-ms: 1.2.1 331 | transitivePeerDependencies: 332 | - supports-color 333 | dev: true 334 | 335 | /ansi-colors@4.1.3: 336 | resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} 337 | engines: {node: '>=6'} 338 | dev: true 339 | 340 | /ansi-regex@5.0.1: 341 | resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} 342 | engines: {node: '>=8'} 343 | dev: true 344 | 345 | /ansi-styles@4.3.0: 346 | resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} 347 | engines: {node: '>=8'} 348 | dependencies: 349 | color-convert: 2.0.1 350 | dev: true 351 | 352 | /arg@5.0.2: 353 | resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} 354 | dev: true 355 | 356 | /asap@2.0.6: 357 | resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} 358 | dev: true 359 | 360 | /asynckit@0.4.0: 361 | resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} 362 | dev: true 363 | 364 | /axios@0.25.0(debug@4.3.4): 365 | resolution: {integrity: sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==} 366 | dependencies: 367 | follow-redirects: 1.15.2(debug@4.3.4) 368 | transitivePeerDependencies: 369 | - debug 370 | dev: true 371 | 372 | /axios@0.27.2(debug@4.3.4): 373 | resolution: {integrity: sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==} 374 | dependencies: 375 | follow-redirects: 1.15.2(debug@4.3.4) 376 | form-data: 4.0.0 377 | transitivePeerDependencies: 378 | - debug 379 | dev: true 380 | 381 | /base-x@3.0.9: 382 | resolution: {integrity: sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==} 383 | dependencies: 384 | safe-buffer: 5.2.1 385 | dev: true 386 | 387 | /base64-js@1.5.1: 388 | resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} 389 | dev: true 390 | 391 | /base64id@2.0.0: 392 | resolution: {integrity: sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==} 393 | engines: {node: ^4.5.0 || >= 5.9} 394 | dev: true 395 | 396 | /bigint-buffer@1.1.5: 397 | resolution: {integrity: sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA==} 398 | engines: {node: '>= 10.0.0'} 399 | requiresBuild: true 400 | dependencies: 401 | bindings: 1.5.0 402 | dev: true 403 | 404 | /bignumber.js@9.1.1: 405 | resolution: {integrity: sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig==} 406 | dev: true 407 | 408 | /bindings@1.5.0: 409 | resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} 410 | dependencies: 411 | file-uri-to-path: 1.0.0 412 | dev: true 413 | 414 | /bluebird@3.7.2: 415 | resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} 416 | dev: true 417 | 418 | /bn.js@5.2.1: 419 | resolution: {integrity: sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==} 420 | dev: true 421 | 422 | /borsh@0.7.0: 423 | resolution: {integrity: sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==} 424 | dependencies: 425 | bn.js: 5.2.1 426 | bs58: 4.0.1 427 | text-encoding-utf-8: 1.0.2 428 | dev: true 429 | 430 | /bs58@4.0.1: 431 | resolution: {integrity: sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==} 432 | dependencies: 433 | base-x: 3.0.9 434 | dev: true 435 | 436 | /buffer-hexdump@1.0.0: 437 | resolution: {integrity: sha512-Zfe5uJT9Y7J2cm2MVkmhRdkAqlbj0uw9oBaeXgOKUiXd+kdcABkp7+W+hQ8fCW/5TouBClXSzD8K5/XwVckDsg==} 438 | dev: true 439 | 440 | /buffer@6.0.3: 441 | resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} 442 | dependencies: 443 | base64-js: 1.5.1 444 | ieee754: 1.2.1 445 | dev: true 446 | 447 | /bufferutil@4.0.7: 448 | resolution: {integrity: sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw==} 449 | engines: {node: '>=6.14.2'} 450 | requiresBuild: true 451 | dependencies: 452 | node-gyp-build: 4.6.0 453 | dev: true 454 | 455 | /call-bind@1.0.7: 456 | resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} 457 | engines: {node: '>= 0.4'} 458 | dependencies: 459 | es-define-property: 1.0.0 460 | es-errors: 1.3.0 461 | function-bind: 1.1.2 462 | get-intrinsic: 1.2.4 463 | set-function-length: 1.2.2 464 | dev: true 465 | 466 | /chalk@4.1.2: 467 | resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} 468 | engines: {node: '>=10'} 469 | dependencies: 470 | ansi-styles: 4.3.0 471 | supports-color: 7.2.0 472 | dev: true 473 | 474 | /chalk@5.3.0: 475 | resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} 476 | engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} 477 | dev: true 478 | 479 | /check-more-types@2.24.0: 480 | resolution: {integrity: sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==} 481 | engines: {node: '>= 0.8.0'} 482 | dev: true 483 | 484 | /cliui@8.0.1: 485 | resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} 486 | engines: {node: '>=12'} 487 | dependencies: 488 | string-width: 4.2.3 489 | strip-ansi: 6.0.1 490 | wrap-ansi: 7.0.0 491 | dev: true 492 | 493 | /color-convert@2.0.1: 494 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} 495 | engines: {node: '>=7.0.0'} 496 | dependencies: 497 | color-name: 1.1.4 498 | dev: true 499 | 500 | /color-name@1.1.4: 501 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} 502 | dev: true 503 | 504 | /combined-stream@1.0.8: 505 | resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} 506 | engines: {node: '>= 0.8'} 507 | dependencies: 508 | delayed-stream: 1.0.0 509 | dev: true 510 | 511 | /commander@12.0.0: 512 | resolution: {integrity: sha512-MwVNWlYjDTtOjX5PiD7o5pK0UrFU/OYgcJfjjK4RaHZETNtjJqrZa9Y9ds88+A+f+d5lv+561eZ+yCKoS3gbAA==} 513 | engines: {node: '>=18'} 514 | dev: true 515 | 516 | /commander@2.20.3: 517 | resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} 518 | dev: true 519 | 520 | /commander@5.1.0: 521 | resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==} 522 | engines: {node: '>= 6'} 523 | dev: true 524 | 525 | /cookie@0.4.2: 526 | resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==} 527 | engines: {node: '>= 0.6'} 528 | dev: true 529 | 530 | /cors@2.8.5: 531 | resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} 532 | engines: {node: '>= 0.10'} 533 | dependencies: 534 | object-assign: 4.1.1 535 | vary: 1.1.2 536 | dev: true 537 | 538 | /cross-fetch@3.0.6: 539 | resolution: {integrity: sha512-KBPUbqgFjzWlVcURG+Svp9TlhA5uliYtiNx/0r8nv0pdypeQCRJ9IaSIc3q/x3q8t3F75cHuwxVql1HFGHCNJQ==} 540 | dependencies: 541 | node-fetch: 2.6.1 542 | dev: true 543 | 544 | /cross-spawn@7.0.3: 545 | resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} 546 | engines: {node: '>= 8'} 547 | dependencies: 548 | path-key: 3.1.1 549 | shebang-command: 2.0.0 550 | which: 2.0.2 551 | dev: true 552 | 553 | /date-fns@2.29.3: 554 | resolution: {integrity: sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==} 555 | engines: {node: '>=0.11'} 556 | dev: true 557 | 558 | /debug@4.3.4: 559 | resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} 560 | engines: {node: '>=6.0'} 561 | peerDependencies: 562 | supports-color: '*' 563 | peerDependenciesMeta: 564 | supports-color: 565 | optional: true 566 | dependencies: 567 | ms: 2.1.2 568 | dev: true 569 | 570 | /deep-diff@1.0.2: 571 | resolution: {integrity: sha512-aWS3UIVH+NPGCD1kki+DCU9Dua032iSsO43LqQpcs4R3+dVv7tX0qBGjiVHJHjplsoUM2XRO/KB92glqc68awg==} 572 | dev: true 573 | 574 | /define-data-property@1.1.4: 575 | resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} 576 | engines: {node: '>= 0.4'} 577 | dependencies: 578 | es-define-property: 1.0.0 579 | es-errors: 1.3.0 580 | gopd: 1.0.1 581 | dev: true 582 | 583 | /delay@5.0.0: 584 | resolution: {integrity: sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==} 585 | engines: {node: '>=10'} 586 | dev: true 587 | 588 | /delayed-stream@1.0.0: 589 | resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} 590 | engines: {node: '>=0.4.0'} 591 | dev: true 592 | 593 | /depd@2.0.0: 594 | resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} 595 | engines: {node: '>= 0.8'} 596 | dev: true 597 | 598 | /diff@5.1.0: 599 | resolution: {integrity: sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==} 600 | engines: {node: '>=0.3.1'} 601 | dev: true 602 | 603 | /duplexer@0.1.2: 604 | resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} 605 | dev: true 606 | 607 | /emoji-regex@8.0.0: 608 | resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} 609 | dev: true 610 | 611 | /engine.io-client@6.4.0: 612 | resolution: {integrity: sha512-GyKPDyoEha+XZ7iEqam49vz6auPnNJ9ZBfy89f+rMMas8AuiMWOZ9PVzu8xb9ZC6rafUqiGHSCfu22ih66E+1g==} 613 | dependencies: 614 | '@socket.io/component-emitter': 3.1.0 615 | debug: 4.3.4 616 | engine.io-parser: 5.0.6 617 | ws: 8.11.0 618 | xmlhttprequest-ssl: 2.0.0 619 | transitivePeerDependencies: 620 | - bufferutil 621 | - supports-color 622 | - utf-8-validate 623 | dev: true 624 | 625 | /engine.io-parser@5.0.6: 626 | resolution: {integrity: sha512-tjuoZDMAdEhVnSFleYPCtdL2GXwVTGtNjoeJd9IhIG3C1xs9uwxqRNEu5WpnDZCaozwVlK/nuQhpodhXSIMaxw==} 627 | engines: {node: '>=10.0.0'} 628 | dev: true 629 | 630 | /engine.io@6.4.1: 631 | resolution: {integrity: sha512-JFYQurD/nbsA5BSPmbaOSLa3tSVj8L6o4srSwXXY3NqE+gGUNmmPTbhn8tjzcCtSqhFgIeqef81ngny8JM25hw==} 632 | engines: {node: '>=10.0.0'} 633 | dependencies: 634 | '@types/cookie': 0.4.1 635 | '@types/cors': 2.8.13 636 | '@types/node': 18.16.1 637 | accepts: 1.3.8 638 | base64id: 2.0.0 639 | cookie: 0.4.2 640 | cors: 2.8.5 641 | debug: 4.3.4 642 | engine.io-parser: 5.0.6 643 | ws: 8.11.0 644 | transitivePeerDependencies: 645 | - bufferutil 646 | - supports-color 647 | - utf-8-validate 648 | dev: true 649 | 650 | /es-define-property@1.0.0: 651 | resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} 652 | engines: {node: '>= 0.4'} 653 | dependencies: 654 | get-intrinsic: 1.2.4 655 | dev: true 656 | 657 | /es-errors@1.3.0: 658 | resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} 659 | engines: {node: '>= 0.4'} 660 | dev: true 661 | 662 | /es6-promise@4.2.8: 663 | resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==} 664 | dev: true 665 | 666 | /es6-promisify@5.0.0: 667 | resolution: {integrity: sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==} 668 | dependencies: 669 | es6-promise: 4.2.8 670 | dev: true 671 | 672 | /escalade@3.1.1: 673 | resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} 674 | engines: {node: '>=6'} 675 | dev: true 676 | 677 | /event-stream@3.3.4: 678 | resolution: {integrity: sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==} 679 | dependencies: 680 | duplexer: 0.1.2 681 | from: 0.1.7 682 | map-stream: 0.1.0 683 | pause-stream: 0.0.11 684 | split: 0.3.3 685 | stream-combiner: 0.0.4 686 | through: 2.3.8 687 | dev: true 688 | 689 | /eventemitter3@4.0.7: 690 | resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} 691 | dev: true 692 | 693 | /execa@5.1.1: 694 | resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} 695 | engines: {node: '>=10'} 696 | dependencies: 697 | cross-spawn: 7.0.3 698 | get-stream: 6.0.1 699 | human-signals: 2.1.0 700 | is-stream: 2.0.1 701 | merge-stream: 2.0.0 702 | npm-run-path: 4.0.1 703 | onetime: 5.1.2 704 | signal-exit: 3.0.7 705 | strip-final-newline: 2.0.0 706 | dev: true 707 | 708 | /eyes@0.1.8: 709 | resolution: {integrity: sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==} 710 | engines: {node: '> 0.1.90'} 711 | dev: true 712 | 713 | /fast-stable-stringify@1.0.0: 714 | resolution: {integrity: sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag==} 715 | dev: true 716 | 717 | /fastestsmallesttextencoderdecoder@1.0.22: 718 | resolution: {integrity: sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw==} 719 | dev: true 720 | 721 | /file-uri-to-path@1.0.0: 722 | resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} 723 | dev: true 724 | 725 | /follow-redirects@1.15.2(debug@4.3.4): 726 | resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==} 727 | engines: {node: '>=4.0'} 728 | peerDependencies: 729 | debug: '*' 730 | peerDependenciesMeta: 731 | debug: 732 | optional: true 733 | dependencies: 734 | debug: 4.3.4 735 | dev: true 736 | 737 | /form-data@4.0.0: 738 | resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} 739 | engines: {node: '>= 6'} 740 | dependencies: 741 | asynckit: 0.4.0 742 | combined-stream: 1.0.8 743 | mime-types: 2.1.35 744 | dev: true 745 | 746 | /from@0.1.7: 747 | resolution: {integrity: sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==} 748 | dev: true 749 | 750 | /function-bind@1.1.2: 751 | resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} 752 | dev: true 753 | 754 | /get-caller-file@2.0.5: 755 | resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} 756 | engines: {node: 6.* || 8.* || >= 10.*} 757 | dev: true 758 | 759 | /get-intrinsic@1.2.4: 760 | resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} 761 | engines: {node: '>= 0.4'} 762 | dependencies: 763 | es-errors: 1.3.0 764 | function-bind: 1.1.2 765 | has-proto: 1.0.3 766 | has-symbols: 1.0.3 767 | hasown: 2.0.2 768 | dev: true 769 | 770 | /get-stream@6.0.1: 771 | resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} 772 | engines: {node: '>=10'} 773 | dev: true 774 | 775 | /gopd@1.0.1: 776 | resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} 777 | dependencies: 778 | get-intrinsic: 1.2.4 779 | dev: true 780 | 781 | /has-flag@4.0.0: 782 | resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} 783 | engines: {node: '>=8'} 784 | dev: true 785 | 786 | /has-property-descriptors@1.0.2: 787 | resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} 788 | dependencies: 789 | es-define-property: 1.0.0 790 | dev: true 791 | 792 | /has-proto@1.0.3: 793 | resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} 794 | engines: {node: '>= 0.4'} 795 | dev: true 796 | 797 | /has-symbols@1.0.3: 798 | resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} 799 | engines: {node: '>= 0.4'} 800 | dev: true 801 | 802 | /hasown@2.0.2: 803 | resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} 804 | engines: {node: '>= 0.4'} 805 | dependencies: 806 | function-bind: 1.1.2 807 | dev: true 808 | 809 | /human-signals@2.1.0: 810 | resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} 811 | engines: {node: '>=10.17.0'} 812 | dev: true 813 | 814 | /humanize-ms@1.2.1: 815 | resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} 816 | dependencies: 817 | ms: 2.1.3 818 | dev: true 819 | 820 | /ieee754@1.2.1: 821 | resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} 822 | dev: true 823 | 824 | /is-fullwidth-code-point@3.0.0: 825 | resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} 826 | engines: {node: '>=8'} 827 | dev: true 828 | 829 | /is-stream@2.0.1: 830 | resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} 831 | engines: {node: '>=8'} 832 | dev: true 833 | 834 | /isarray@2.0.5: 835 | resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} 836 | dev: true 837 | 838 | /isexe@2.0.0: 839 | resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} 840 | dev: true 841 | 842 | /isomorphic-ws@4.0.1(ws@7.5.9): 843 | resolution: {integrity: sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==} 844 | peerDependencies: 845 | ws: '*' 846 | dependencies: 847 | ws: 7.5.9 848 | dev: true 849 | 850 | /jayson@3.7.0: 851 | resolution: {integrity: sha512-tfy39KJMrrXJ+mFcMpxwBvFDetS8LAID93+rycFglIQM4kl3uNR3W4lBLE/FFhsoUCEox5Dt2adVpDm/XtebbQ==} 852 | engines: {node: '>=8'} 853 | hasBin: true 854 | dependencies: 855 | '@types/connect': 3.4.35 856 | '@types/node': 12.20.55 857 | '@types/ws': 7.4.7 858 | JSONStream: 1.3.5 859 | commander: 2.20.3 860 | delay: 5.0.0 861 | es6-promisify: 5.0.0 862 | eyes: 0.1.8 863 | isomorphic-ws: 4.0.1(ws@7.5.9) 864 | json-stringify-safe: 5.0.1 865 | lodash: 4.17.21 866 | uuid: 8.3.2 867 | ws: 7.5.9 868 | transitivePeerDependencies: 869 | - bufferutil 870 | - utf-8-validate 871 | dev: true 872 | 873 | /joi@17.9.2: 874 | resolution: {integrity: sha512-Itk/r+V4Dx0V3c7RLFdRh12IOjySm2/WGPMubBT92cQvRfYZhPM2W0hZlctjj72iES8jsRCwp7S/cRmWBnJ4nw==} 875 | dependencies: 876 | '@hapi/hoek': 9.3.0 877 | '@hapi/topo': 5.1.0 878 | '@sideway/address': 4.1.4 879 | '@sideway/formula': 3.0.1 880 | '@sideway/pinpoint': 2.0.0 881 | dev: true 882 | 883 | /js-sha3@0.8.0: 884 | resolution: {integrity: sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==} 885 | dev: true 886 | 887 | /json-stable-stringify@1.1.1: 888 | resolution: {integrity: sha512-SU/971Kt5qVQfJpyDveVhQ/vya+5hvrjClFOcr8c0Fq5aODJjMwutrOfCU+eCnVD5gpx1Q3fEqkyom77zH1iIg==} 889 | engines: {node: '>= 0.4'} 890 | dependencies: 891 | call-bind: 1.0.7 892 | isarray: 2.0.5 893 | jsonify: 0.0.1 894 | object-keys: 1.1.1 895 | dev: true 896 | 897 | /json-stringify-safe@5.0.1: 898 | resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} 899 | dev: true 900 | 901 | /jsonify@0.0.1: 902 | resolution: {integrity: sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==} 903 | dev: true 904 | 905 | /jsonparse@1.3.1: 906 | resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==} 907 | engines: {'0': node >= 0.2.0} 908 | dev: true 909 | 910 | /lazy-ass@1.6.0: 911 | resolution: {integrity: sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==} 912 | engines: {node: '> 0.8'} 913 | dev: true 914 | 915 | /lodash@4.17.21: 916 | resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} 917 | dev: true 918 | 919 | /lru-cache@6.0.0: 920 | resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} 921 | engines: {node: '>=10'} 922 | dependencies: 923 | yallist: 4.0.0 924 | dev: true 925 | 926 | /make-synchronized@0.2.9: 927 | resolution: {integrity: sha512-4wczOs8SLuEdpEvp3vGo83wh8rjJ78UsIk7DIX5fxdfmfMJGog4bQzxfvOwq7Q3yCHLC4jp1urPHIxRS/A93gA==} 928 | dev: true 929 | 930 | /map-stream@0.1.0: 931 | resolution: {integrity: sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==} 932 | dev: true 933 | 934 | /merge-stream@2.0.0: 935 | resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} 936 | dev: true 937 | 938 | /mime-db@1.52.0: 939 | resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} 940 | engines: {node: '>= 0.6'} 941 | dev: true 942 | 943 | /mime-types@2.1.35: 944 | resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} 945 | engines: {node: '>= 0.6'} 946 | dependencies: 947 | mime-db: 1.52.0 948 | dev: true 949 | 950 | /mimic-fn@2.1.0: 951 | resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} 952 | engines: {node: '>=6'} 953 | dev: true 954 | 955 | /minimist@1.2.8: 956 | resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} 957 | dev: true 958 | 959 | /ms@2.1.2: 960 | resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} 961 | dev: true 962 | 963 | /ms@2.1.3: 964 | resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} 965 | dev: true 966 | 967 | /negotiator@0.6.3: 968 | resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} 969 | engines: {node: '>= 0.6'} 970 | dev: true 971 | 972 | /netstats@0.0.6: 973 | resolution: {integrity: sha512-j5sdwaoLX/0x74+8bFdnoVEo3RUQexm5Lw615MVrgx7/FSQx88dZj+t5whwrDSrlsiHMYhKpn52p/6oMYHTZ2A==} 974 | engines: {node: '>=8'} 975 | dev: true 976 | 977 | /node-fetch@2.6.1: 978 | resolution: {integrity: sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==} 979 | engines: {node: 4.x || >=6.0.0} 980 | dev: true 981 | 982 | /node-fetch@2.6.9: 983 | resolution: {integrity: sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==} 984 | engines: {node: 4.x || >=6.0.0} 985 | peerDependencies: 986 | encoding: ^0.1.0 987 | peerDependenciesMeta: 988 | encoding: 989 | optional: true 990 | dependencies: 991 | whatwg-url: 5.0.0 992 | dev: true 993 | 994 | /node-gyp-build@4.6.0: 995 | resolution: {integrity: sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==} 996 | hasBin: true 997 | requiresBuild: true 998 | dev: true 999 | 1000 | /npm-run-path@4.0.1: 1001 | resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} 1002 | engines: {node: '>=8'} 1003 | dependencies: 1004 | path-key: 3.1.1 1005 | dev: true 1006 | 1007 | /numeral@2.0.6: 1008 | resolution: {integrity: sha512-qaKRmtYPZ5qdw4jWJD6bxEf1FJEqllJrwxCLIm0sQU/A7v2/czigzOb+C2uSiFsa9lBUzeH7M1oK+Q+OLxL3kA==} 1009 | dev: true 1010 | 1011 | /nunjucks@3.2.4: 1012 | resolution: {integrity: sha512-26XRV6BhkgK0VOxfbU5cQI+ICFUtMLixv1noZn1tGU38kQH5A5nmmbk/O45xdyBhD1esk47nKrY0mvQpZIhRjQ==} 1013 | engines: {node: '>= 6.9.0'} 1014 | hasBin: true 1015 | peerDependencies: 1016 | chokidar: ^3.3.0 1017 | peerDependenciesMeta: 1018 | chokidar: 1019 | optional: true 1020 | dependencies: 1021 | a-sync-waterfall: 1.0.1 1022 | asap: 2.0.6 1023 | commander: 5.1.0 1024 | dev: true 1025 | 1026 | /object-assign@4.1.1: 1027 | resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} 1028 | engines: {node: '>=0.10.0'} 1029 | dev: true 1030 | 1031 | /object-keys@1.1.1: 1032 | resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} 1033 | engines: {node: '>= 0.4'} 1034 | dev: true 1035 | 1036 | /onetime@5.1.2: 1037 | resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} 1038 | engines: {node: '>=6'} 1039 | dependencies: 1040 | mimic-fn: 2.1.0 1041 | dev: true 1042 | 1043 | /path-key@3.1.1: 1044 | resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} 1045 | engines: {node: '>=8'} 1046 | dev: true 1047 | 1048 | /pause-stream@0.0.11: 1049 | resolution: {integrity: sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==} 1050 | dependencies: 1051 | through: 2.3.8 1052 | dev: true 1053 | 1054 | /port-pid@0.0.7: 1055 | resolution: {integrity: sha512-2QkdCeuGLfu1jDxiiwOnafCgVFsMQXMEWvUVx9SMNq+4k6HDKiyA9YVRhmoMvJGg5ZhqEjblpj+1wdWMqn7scw==} 1056 | engines: {node: '>=8'} 1057 | dependencies: 1058 | netstats: 0.0.6 1059 | selective-whitespace: 1.0.4 1060 | dev: true 1061 | 1062 | /prettier@3.2.5: 1063 | resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==} 1064 | engines: {node: '>=14'} 1065 | hasBin: true 1066 | dev: true 1067 | 1068 | /ps-tree@1.2.0: 1069 | resolution: {integrity: sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==} 1070 | engines: {node: '>= 0.10'} 1071 | hasBin: true 1072 | dependencies: 1073 | event-stream: 3.3.4 1074 | dev: true 1075 | 1076 | /regenerator-runtime@0.13.11: 1077 | resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} 1078 | dev: true 1079 | 1080 | /require-directory@2.1.1: 1081 | resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} 1082 | engines: {node: '>=0.10.0'} 1083 | dev: true 1084 | 1085 | /rpc-websockets@7.5.1: 1086 | resolution: {integrity: sha512-kGFkeTsmd37pHPMaHIgN1LVKXMi0JD782v4Ds9ZKtLlwdTKjn+CxM9A9/gLT2LaOuEcEFGL98h1QWQtlOIdW0w==} 1087 | dependencies: 1088 | '@babel/runtime': 7.21.0 1089 | eventemitter3: 4.0.7 1090 | uuid: 8.3.2 1091 | ws: 8.13.0(bufferutil@4.0.7)(utf-8-validate@5.0.10) 1092 | optionalDependencies: 1093 | bufferutil: 4.0.7 1094 | utf-8-validate: 5.0.10 1095 | dev: true 1096 | 1097 | /rxjs@7.8.0: 1098 | resolution: {integrity: sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==} 1099 | dependencies: 1100 | tslib: 2.5.0 1101 | dev: true 1102 | 1103 | /safe-buffer@5.2.1: 1104 | resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} 1105 | dev: true 1106 | 1107 | /selective-whitespace@1.0.4: 1108 | resolution: {integrity: sha512-DyL/pLbb9poQNQOVndVohclAO8lq+6gEBW8q3H9c2fX+ODkugQMvjBilPjw09lrIuVRFRQ/nwhLdzn60sFh9lQ==} 1109 | dependencies: 1110 | tokenize-whitespace: 0.0.1 1111 | dev: true 1112 | 1113 | /semver@7.5.0: 1114 | resolution: {integrity: sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==} 1115 | engines: {node: '>=10'} 1116 | hasBin: true 1117 | dependencies: 1118 | lru-cache: 6.0.0 1119 | dev: true 1120 | 1121 | /set-function-length@1.2.2: 1122 | resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} 1123 | engines: {node: '>= 0.4'} 1124 | dependencies: 1125 | define-data-property: 1.1.4 1126 | es-errors: 1.3.0 1127 | function-bind: 1.1.2 1128 | get-intrinsic: 1.2.4 1129 | gopd: 1.0.1 1130 | has-property-descriptors: 1.0.2 1131 | dev: true 1132 | 1133 | /shebang-command@2.0.0: 1134 | resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} 1135 | engines: {node: '>=8'} 1136 | dependencies: 1137 | shebang-regex: 3.0.0 1138 | dev: true 1139 | 1140 | /shebang-regex@3.0.0: 1141 | resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} 1142 | engines: {node: '>=8'} 1143 | dev: true 1144 | 1145 | /signal-exit@3.0.7: 1146 | resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} 1147 | dev: true 1148 | 1149 | /socket.io-adapter@2.5.2: 1150 | resolution: {integrity: sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==} 1151 | dependencies: 1152 | ws: 8.11.0 1153 | transitivePeerDependencies: 1154 | - bufferutil 1155 | - utf-8-validate 1156 | dev: true 1157 | 1158 | /socket.io-client@4.6.1: 1159 | resolution: {integrity: sha512-5UswCV6hpaRsNg5kkEHVcbBIXEYoVbMQaHJBXJCyEQ+CiFPV1NIOY0XOFWG4XR4GZcB8Kn6AsRs/9cy9TbqVMQ==} 1160 | engines: {node: '>=10.0.0'} 1161 | dependencies: 1162 | '@socket.io/component-emitter': 3.1.0 1163 | debug: 4.3.4 1164 | engine.io-client: 6.4.0 1165 | socket.io-parser: 4.2.2 1166 | transitivePeerDependencies: 1167 | - bufferutil 1168 | - supports-color 1169 | - utf-8-validate 1170 | dev: true 1171 | 1172 | /socket.io-parser@4.2.2: 1173 | resolution: {integrity: sha512-DJtziuKypFkMMHCm2uIshOYC7QaylbtzQwiMYDuCKy3OPkjLzu4B2vAhTlqipRHHzrI0NJeBAizTK7X+6m1jVw==} 1174 | engines: {node: '>=10.0.0'} 1175 | dependencies: 1176 | '@socket.io/component-emitter': 3.1.0 1177 | debug: 4.3.4 1178 | transitivePeerDependencies: 1179 | - supports-color 1180 | dev: true 1181 | 1182 | /socket.io@4.6.1: 1183 | resolution: {integrity: sha512-KMcaAi4l/8+xEjkRICl6ak8ySoxsYG+gG6/XfRCPJPQ/haCRIJBTL4wIl8YCsmtaBovcAXGLOShyVWQ/FG8GZA==} 1184 | engines: {node: '>=10.0.0'} 1185 | dependencies: 1186 | accepts: 1.3.8 1187 | base64id: 2.0.0 1188 | debug: 4.3.4 1189 | engine.io: 6.4.1 1190 | socket.io-adapter: 2.5.2 1191 | socket.io-parser: 4.2.2 1192 | transitivePeerDependencies: 1193 | - bufferutil 1194 | - supports-color 1195 | - utf-8-validate 1196 | dev: true 1197 | 1198 | /split@0.3.3: 1199 | resolution: {integrity: sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==} 1200 | dependencies: 1201 | through: 2.3.8 1202 | dev: true 1203 | 1204 | /start-server-and-test@1.15.4: 1205 | resolution: {integrity: sha512-ucQtp5+UCr0m4aHlY+aEV2JSYNTiMZKdSKK/bsIr6AlmwAWDYDnV7uGlWWEtWa7T4XvRI5cPYcPcQgeLqpz+Tg==} 1206 | engines: {node: '>=6'} 1207 | hasBin: true 1208 | dependencies: 1209 | arg: 5.0.2 1210 | bluebird: 3.7.2 1211 | check-more-types: 2.24.0 1212 | debug: 4.3.4 1213 | execa: 5.1.1 1214 | lazy-ass: 1.6.0 1215 | ps-tree: 1.2.0 1216 | wait-on: 7.0.1(debug@4.3.4) 1217 | transitivePeerDependencies: 1218 | - supports-color 1219 | dev: true 1220 | 1221 | /stream-combiner@0.0.4: 1222 | resolution: {integrity: sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==} 1223 | dependencies: 1224 | duplexer: 0.1.2 1225 | dev: true 1226 | 1227 | /string-width@4.2.3: 1228 | resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} 1229 | engines: {node: '>=8'} 1230 | dependencies: 1231 | emoji-regex: 8.0.0 1232 | is-fullwidth-code-point: 3.0.0 1233 | strip-ansi: 6.0.1 1234 | dev: true 1235 | 1236 | /strip-ansi@6.0.1: 1237 | resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} 1238 | engines: {node: '>=8'} 1239 | dependencies: 1240 | ansi-regex: 5.0.1 1241 | dev: true 1242 | 1243 | /strip-final-newline@2.0.0: 1244 | resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} 1245 | engines: {node: '>=6'} 1246 | dev: true 1247 | 1248 | /superstruct@0.14.2: 1249 | resolution: {integrity: sha512-nPewA6m9mR3d6k7WkZ8N8zpTWfenFH3q9pA2PkuiZxINr9DKB2+40wEQf0ixn8VaGuJ78AB6iWOtStI+/4FKZQ==} 1250 | dev: true 1251 | 1252 | /supports-color@7.2.0: 1253 | resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} 1254 | engines: {node: '>=8'} 1255 | dependencies: 1256 | has-flag: 4.0.0 1257 | dev: true 1258 | 1259 | /text-encoding-utf-8@1.0.2: 1260 | resolution: {integrity: sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==} 1261 | dev: true 1262 | 1263 | /text-table@0.2.0: 1264 | resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} 1265 | dev: true 1266 | 1267 | /through@2.3.8: 1268 | resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} 1269 | dev: true 1270 | 1271 | /timeago.js@4.0.2: 1272 | resolution: {integrity: sha512-a7wPxPdVlQL7lqvitHGGRsofhdwtkoSXPGATFuSOA2i1ZNQEPLrGnj68vOp2sOJTCFAQVXPeNMX/GctBaO9L2w==} 1273 | dev: true 1274 | 1275 | /tokenize-whitespace@0.0.1: 1276 | resolution: {integrity: sha512-OxbdMHTjVs0ccBMfjo1v5OH6bq8yhydewCd9n6xihgtZvI3wSqR00EsM86DjELLl6VtMkY2z99r5q+uNW79E+Q==} 1277 | dev: true 1278 | 1279 | /toml@3.0.0: 1280 | resolution: {integrity: sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==} 1281 | dev: true 1282 | 1283 | /tr46@0.0.3: 1284 | resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} 1285 | dev: true 1286 | 1287 | /ts-essentials@9.3.1(typescript@4.9.5): 1288 | resolution: {integrity: sha512-9CChSvQMyVRo29Vb1A2jbs+LKo3d/bAf+ndSaX0T8cEiy/HChVaRN/HY5DqUryZ8hZ6uol9bEgCnGmnDbwBR9Q==} 1289 | peerDependencies: 1290 | typescript: '>=4.1.0' 1291 | dependencies: 1292 | typescript: 4.9.5 1293 | dev: true 1294 | 1295 | /tslib@2.5.0: 1296 | resolution: {integrity: sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==} 1297 | dev: true 1298 | 1299 | /tweetnacl@1.0.3: 1300 | resolution: {integrity: sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==} 1301 | dev: true 1302 | 1303 | /typescript@4.9.5: 1304 | resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} 1305 | engines: {node: '>=4.2.0'} 1306 | hasBin: true 1307 | dev: true 1308 | 1309 | /utf-8-validate@5.0.10: 1310 | resolution: {integrity: sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==} 1311 | engines: {node: '>=6.14.2'} 1312 | requiresBuild: true 1313 | dependencies: 1314 | node-gyp-build: 4.6.0 1315 | dev: true 1316 | 1317 | /uuid@8.3.2: 1318 | resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} 1319 | hasBin: true 1320 | dev: true 1321 | 1322 | /vary@1.1.2: 1323 | resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} 1324 | engines: {node: '>= 0.8'} 1325 | dev: true 1326 | 1327 | /wait-on@6.0.1(debug@4.3.4): 1328 | resolution: {integrity: sha512-zht+KASY3usTY5u2LgaNqn/Cd8MukxLGjdcZxT2ns5QzDmTFc4XoWBgC+C/na+sMRZTuVygQoMYwdcVjHnYIVw==} 1329 | engines: {node: '>=10.0.0'} 1330 | hasBin: true 1331 | dependencies: 1332 | axios: 0.25.0(debug@4.3.4) 1333 | joi: 17.9.2 1334 | lodash: 4.17.21 1335 | minimist: 1.2.8 1336 | rxjs: 7.8.0 1337 | transitivePeerDependencies: 1338 | - debug 1339 | dev: true 1340 | 1341 | /wait-on@7.0.1(debug@4.3.4): 1342 | resolution: {integrity: sha512-9AnJE9qTjRQOlTZIldAaf/da2eW0eSRSgcqq85mXQja/DW3MriHxkpODDSUEg+Gri/rKEcXUZHe+cevvYItaog==} 1343 | engines: {node: '>=12.0.0'} 1344 | hasBin: true 1345 | dependencies: 1346 | axios: 0.27.2(debug@4.3.4) 1347 | joi: 17.9.2 1348 | lodash: 4.17.21 1349 | minimist: 1.2.8 1350 | rxjs: 7.8.0 1351 | transitivePeerDependencies: 1352 | - debug 1353 | dev: true 1354 | 1355 | /webidl-conversions@3.0.1: 1356 | resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} 1357 | dev: true 1358 | 1359 | /whatwg-url@5.0.0: 1360 | resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} 1361 | dependencies: 1362 | tr46: 0.0.3 1363 | webidl-conversions: 3.0.1 1364 | dev: true 1365 | 1366 | /which@2.0.2: 1367 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} 1368 | engines: {node: '>= 8'} 1369 | hasBin: true 1370 | dependencies: 1371 | isexe: 2.0.0 1372 | dev: true 1373 | 1374 | /wrap-ansi@7.0.0: 1375 | resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} 1376 | engines: {node: '>=10'} 1377 | dependencies: 1378 | ansi-styles: 4.3.0 1379 | string-width: 4.2.3 1380 | strip-ansi: 6.0.1 1381 | dev: true 1382 | 1383 | /ws@7.5.9: 1384 | resolution: {integrity: sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==} 1385 | engines: {node: '>=8.3.0'} 1386 | peerDependencies: 1387 | bufferutil: ^4.0.1 1388 | utf-8-validate: ^5.0.2 1389 | peerDependenciesMeta: 1390 | bufferutil: 1391 | optional: true 1392 | utf-8-validate: 1393 | optional: true 1394 | dev: true 1395 | 1396 | /ws@8.11.0: 1397 | resolution: {integrity: sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==} 1398 | engines: {node: '>=10.0.0'} 1399 | peerDependencies: 1400 | bufferutil: ^4.0.1 1401 | utf-8-validate: ^5.0.2 1402 | peerDependenciesMeta: 1403 | bufferutil: 1404 | optional: true 1405 | utf-8-validate: 1406 | optional: true 1407 | dev: true 1408 | 1409 | /ws@8.13.0(bufferutil@4.0.7)(utf-8-validate@5.0.10): 1410 | resolution: {integrity: sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==} 1411 | engines: {node: '>=10.0.0'} 1412 | peerDependencies: 1413 | bufferutil: ^4.0.1 1414 | utf-8-validate: '>=5.0.2' 1415 | peerDependenciesMeta: 1416 | bufferutil: 1417 | optional: true 1418 | utf-8-validate: 1419 | optional: true 1420 | dependencies: 1421 | bufferutil: 4.0.7 1422 | utf-8-validate: 5.0.10 1423 | dev: true 1424 | 1425 | /xmlhttprequest-ssl@2.0.0: 1426 | resolution: {integrity: sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==} 1427 | engines: {node: '>=0.4.0'} 1428 | dev: true 1429 | 1430 | /y18n@5.0.8: 1431 | resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} 1432 | engines: {node: '>=10'} 1433 | dev: true 1434 | 1435 | /yallist@4.0.0: 1436 | resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} 1437 | dev: true 1438 | 1439 | /yargs-parser@21.1.1: 1440 | resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} 1441 | engines: {node: '>=12'} 1442 | dev: true 1443 | 1444 | /yargs@17.7.1: 1445 | resolution: {integrity: sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==} 1446 | engines: {node: '>=12'} 1447 | dependencies: 1448 | cliui: 8.0.1 1449 | escalade: 3.1.1 1450 | get-caller-file: 2.0.5 1451 | require-directory: 2.1.1 1452 | string-width: 4.2.3 1453 | y18n: 5.0.8 1454 | yargs-parser: 21.1.1 1455 | dev: true 1456 | --------------------------------------------------------------------------------