From 9bd878feca4ab575a820eb0c45ae448b33866e0c Mon Sep 17 00:00:00 2001 From: Jon Gurary <91919816+jgur-psyops@users.noreply.github.com> Date: Thu, 22 Aug 2024 12:58:32 -0400 Subject: [PATCH] Fix padding, add anchor tests (#236) * Basic framework for TS integration tests * TS tests for init and config ixes, addBank test wip * Mock oracle, wip add bank happy path testing * WIP decoding bank from raw buffer * Banks now decode with anchor * WIP decoding bank config with enum alignment * Add silly hack to risk tier representation in Rust to force anchor to properly deserialize it. * cleanup msg * Various minor fixes * Restore one-byte RiskTier, WIP test mainnet structs decode correctly * WIP mainnet decode test * Taste the rainbow (in console output) * chore: fmt * lint: revert obsolete changes * Manually check fields in mainnet decode test * Attempt to add anchor test to CI jobs * Anchor test CI attempt 2 * Anchor test CI attempt 3 * Anchor test CI attempt 4 * Anchor test CI attempt 5 * Anchor test CI attempt 6 * feat: combine bank padding fields * Mainnet test accounts, CI attempt 6ish * Anchor test CI attempt 8 * Anchor test CI attempt 9 * test: add comprehensive struct regression test with latest fields as of t22 commit * test: add missing account data file * fmt: remove comments for diff clarity * fmt: remove comments for diff clarity * fmt: remove comments for diff clarity * ci: silence wip localnet tests * chore: cleanup * cli: switchboard inspect command * cli: swb pull variant for oracle setup * cli: clearer variant name * chore: utility scripts * ci: revert script change --------- Co-authored-by: man0s <95379755+losman0s@users.noreply.github.com> --- .github/workflows/test.yaml | 43 + .gitignore | 6 +- Anchor.toml | 16 +- Cargo.lock | 11 + README.md | 29 +- clients/rust/marginfi-cli/Cargo.toml | 1 + clients/rust/marginfi-cli/src/entrypoint.rs | 19 +- .../rust/marginfi-cli/src/processor/mod.rs | 22 - .../rust/marginfi-cli/src/processor/oracle.rs | 62 +- package.json | 42 +- programs/marginfi/src/constants.rs | 3 +- programs/marginfi/src/lib.rs | 2 +- programs/marginfi/src/state/marginfi_group.rs | 30 +- .../tests/admin_actions/setup_bank.rs | 2 + .../fixtures/bank/bank_pyusd_230822.json | 14 + programs/marginfi/tests/misc/regression.rs | 163 ++- programs/mocks/Cargo.toml | 31 + programs/mocks/src/errors.rs | 7 + programs/mocks/src/instructions/do_nothing.rs | 14 + .../mocks/src/instructions/init_pool_auth.rs | 71 ++ programs/mocks/src/instructions/mod.rs | 7 + .../src/instructions/swap_like_jupiter.rs | 75 ++ programs/mocks/src/lib.rs | 53 + programs/mocks/src/macros.rs | 10 + programs/mocks/src/state/mod.rs | 3 + programs/mocks/src/state/pool_auth.rs | 15 + scripts/build-program-verifiable.sh | 4 +- scripts/build-program.sh | 8 +- scripts/deploy-buffer.sh | 17 +- scripts/deploy-staging-program.sh | 5 +- ...xWvnbbaVB4zFrf4hoq7Q8z1ZT14co42BGwGtfM.bin | Bin 0 -> 1864 bytes ...2K4AQJEG.bin => pyth_legacy_sol_price.bin} | Bin ...y7eJotD.bin => pyth_legacy_usdc_price.bin} | Bin ...eKvJ1pjLiE.bin => pyth_push_sol_price.bin} | Bin ...Xa2giy9PLeP.bin => swb_pull_sol_price.bin} | Bin test-utils/src/test.rs | 8 +- tests/01_initGroup.spec.ts | 33 + tests/02_configGroup.spec.ts | 68 + tests/03_addBank.spec.ts | 293 +++++ tests/fixtures/bonk_bank.json | 14 + tests/fixtures/cloud_bank.json | 14 + tests/marginfi.ts | 16 - tests/rootHooks.ts | 117 ++ tests/utils/genericTests.ts | 175 +++ tests/utils/instructions.ts | 123 ++ tests/utils/mocks.ts | 347 +++++ tests/utils/pdas.ts | 52 + tests/utils/pyth_mocks.ts | 446 +++++++ tests/utils/tools.ts | 78 ++ tests/utils/types.ts | 110 ++ tsconfig.json | 7 +- yarn.lock | 1112 +++++++++++++---- 52 files changed, 3466 insertions(+), 332 deletions(-) create mode 100644 programs/marginfi/tests/fixtures/bank/bank_pyusd_230822.json create mode 100644 programs/mocks/Cargo.toml create mode 100644 programs/mocks/src/errors.rs create mode 100644 programs/mocks/src/instructions/do_nothing.rs create mode 100644 programs/mocks/src/instructions/init_pool_auth.rs create mode 100644 programs/mocks/src/instructions/mod.rs create mode 100644 programs/mocks/src/instructions/swap_like_jupiter.rs create mode 100644 programs/mocks/src/lib.rs create mode 100644 programs/mocks/src/macros.rs create mode 100644 programs/mocks/src/state/mod.rs create mode 100644 programs/mocks/src/state/pool_auth.rs create mode 100644 test-utils/data/DeyH7QxWvnbbaVB4zFrf4hoq7Q8z1ZT14co42BGwGtfM.bin rename test-utils/data/{H6ARHf6YXhGYeQfUzQNGk6rDNnLBQKrenN712K4AQJEG.bin => pyth_legacy_sol_price.bin} (100%) rename test-utils/data/{Gnt27xtC473ZT2Mw5u8wZ68Z3gULkSTb5DuxJy7eJotD.bin => pyth_legacy_usdc_price.bin} (100%) rename test-utils/data/{7UVimffxr9ow1uXYxsr4LHAcV58mLzhmwaeKvJ1pjLiE.bin => pyth_push_sol_price.bin} (100%) rename test-utils/data/{BSzfJs4d1tAkSDqkepnfzEVcx2WtDVnwwXa2giy9PLeP.bin => swb_pull_sol_price.bin} (100%) create mode 100644 tests/01_initGroup.spec.ts create mode 100644 tests/02_configGroup.spec.ts create mode 100644 tests/03_addBank.spec.ts create mode 100644 tests/fixtures/bonk_bank.json create mode 100644 tests/fixtures/cloud_bank.json delete mode 100644 tests/marginfi.ts create mode 100644 tests/rootHooks.ts create mode 100644 tests/utils/genericTests.ts create mode 100644 tests/utils/instructions.ts create mode 100644 tests/utils/mocks.ts create mode 100644 tests/utils/pdas.ts create mode 100644 tests/utils/pyth_mocks.ts create mode 100644 tests/utils/tools.ts create mode 100644 tests/utils/types.ts diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 14b6db377..519b28673 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -114,3 +114,46 @@ jobs: cargo +nightly-2024-06-05 fuzz run lend -Zbuild-std --strip-dead-code --no-cfg-fuzzing -- -max_total_time=300 - name: Pass after fuzzing run: echo "Fuzzing completed" + + # localnet-test-marginfi: + # name: Anchor localnet tests marginfi + # runs-on: ubuntu-latest + + # steps: + # - uses: actions/checkout@v3 + + # - uses: ./.github/actions/setup-common/ + # - uses: ./.github/actions/setup-anchor-cli/ + + # - uses: ./.github/actions/build-workspace/ + + # - name: Install Node.js dependencies + # run: yarn install + + # - name: Build marginfi program + # run: anchor build -p marginfi -- --no-default-features + + # - name: Build liquidity incentive program + # run: anchor build -p liquidity_incentive_program -- --no-default-features + + # - name: Build mocks program + # run: anchor build -p mocks + + # - name: Start Solana Test Validator + # run: | + # solana-test-validator --reset --limit-ledger-size 1000 \ + + # - name: Wait for Validator to Start + # run: sleep 60 + + # - name: Deploy Liquidity Incentive Program + # run: solana program deploy --program-id Lip1111111111111111111111111111111111111111 target/deploy/liquidity_incentive_program.so + + # - name: Deploy Marginfi Program + # run: solana program deploy --program-id 2jGhuVUuy3umdzByFx8sNWUAaf5vaeuDm78RDPEnhrMr target/deploy/marginfi.so + + # - name: Deploy Mocks Program + # run: solana program deploy --program-id 5XaaR94jBubdbrRrNW7DtRvZeWvLhSHkEGU3jHTEXV3C target/deploy/mocks.so + + # - name: Run tests + # run: anchor test --skip-build --skip-local-validator diff --git a/.gitignore b/.gitignore index 07e6e2c18..9f44766f6 100644 --- a/.gitignore +++ b/.gitignore @@ -27,4 +27,8 @@ test-ledger/ *.profraw # keypairs -*.json \ No newline at end of file +*.json + +# Allow specific json files +!tests/fixtures/**/*.json +!programs/marginfi/tests/fixtures/**/*.json diff --git a/Anchor.toml b/Anchor.toml index ea06333a6..8afc1f917 100644 --- a/Anchor.toml +++ b/Anchor.toml @@ -8,7 +8,8 @@ skip-lint = false [programs.localnet] liquidity_incentive_program = "Lip1111111111111111111111111111111111111111" -marginfi = "Mfi1111111111111111111111111111111111111111" +marginfi = "2jGhuVUuy3umdzByFx8sNWUAaf5vaeuDm78RDPEnhrMr" +mocks = "5XaaR94jBubdbrRrNW7DtRvZeWvLhSHkEGU3jHTEXV3C" [programs.mainnet] liquidity_incentive_program = "LipsxuAkFkwa4RKNzn51wAsW7Dedzt1RNHMkTkDEZUW" @@ -18,11 +19,12 @@ marginfi = "MFv2hWf31Z9kbCa1snEPYctwafyhdvnV7FZnsebVacA" url = "https://api.apr.dev" [provider] -cluster = "https://devnet.rpcpool.com/" +cluster = "localnet" +# cluster = "https://devnet.rpcpool.com/" wallet = "~/.config/solana/id.json" [scripts] -test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts" +test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/*.spec.ts --exit --require tests/rootHooks.ts" [test] startup_wait = 5000 @@ -34,6 +36,14 @@ bind_address = "0.0.0.0" ledger = ".anchor/test-ledger" rpc_port = 8899 +[[test.validator.account]] +address = "DeyH7QxWvnbbaVB4zFrf4hoq7Q8z1ZT14co42BGwGtfM" +filename = "tests/fixtures/bonk_bank.json" + +[[test.validator.account]] +address = "4kNXetv8hSv9PzvzPZzEs1CTH6ARRRi2b8h6jk1ad1nP" +filename = "tests/fixtures/cloud_bank.json" + [[test.validator.account]] address = "8FRFC6MoGGkMFQwngccyu69VnYbzykGeez7ignHVAFSN" filename = "tests/fixtures/localnet_usdc.json" diff --git a/Cargo.lock b/Cargo.lock index 5d4f07ba0..0eaf5addf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2954,6 +2954,7 @@ dependencies = [ "solana-sdk", "spl-associated-token-account 2.3.0", "spl-token 4.0.0", + "switchboard-on-demand", "switchboard-solana", "type-layout", ] @@ -3097,6 +3098,16 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "mocks" +version = "0.1.0" +dependencies = [ + "anchor-lang 0.30.1", + "anchor-spl 0.30.1", + "bytemuck", + "static_assertions", +] + [[package]] name = "modular-bitfield" version = "0.11.2" diff --git a/README.md b/README.md index df10a22db..a3c19641d 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ Marginfi is a decentralized liquidity aggregation protocol built on the Solana blockchain that allows users to access a range of lending markets through a single platform, supporting cryptocurrencies such as SOL, USDC, USDT, wBTC (Portal), ETH (Portal), and BONK. The platform pools liquidity from various sources, offering competitive interest rates to lenders and lower interest rates to borrowers. Marginfi plans to introduce cross-composing in the future, enabling users to trade between different assets on the platform, further enhancing liquidity and providing more opportunities for investment returns. ## Installation + > :warning: marginfi-v2 only compiles on the x86_64 architecture. This is to > ensure struct sizes are always backwards compatible between the SVM and local > development. Ensure the x86_64 arch is enabled before compiling the project. @@ -68,16 +69,38 @@ Install the `solana-verify` tool [here](https://github.com/Ellipsis-Labs/solana- Run `./scripts/verify_mainnet.sh` ## Testing + Integration tests for the on-chain marginfi programs are located under -`/programs/marginfi/tests`. To run the tests, use `cargo test-bpf`. Be sure to +`/programs/marginfi/tests`. To run the tests, use `cargo test-bpf`. Be sure to use an x86 toolchain when compiling and running the tests. +## Rust Tests + Run the full test suite with `.scripts/test-program.sh ` -* e.g. `.scripts/test-program.sh all --sane` + +- e.g. `.scripts/test-program.sh all --sane` Run a single test: `.scripts/test-program.sh ` -* e.g. `.scripts/test-program.sh marginfi configure_bank_success --verbose` + +- e.g. `.scripts/test-program.sh marginfi configure_bank_success --verbose` + +## Localnet Anchor Tests + +Build the program with: + +`anchor build -p marginfi -- --no-default-features` + +You may also need to build the liquidity incentive program and mock program: + +- `anchor build -p mocks` +- `anchor build -p liquidity_incentive_program -- --no-default-features` + +Remember to `yarn install` + +Run the tests: + +`anchor test --skip-build` ## Footguns diff --git a/clients/rust/marginfi-cli/Cargo.toml b/clients/rust/marginfi-cli/Cargo.toml index f3b8ad0e5..0a0d7f738 100644 --- a/clients/rust/marginfi-cli/Cargo.toml +++ b/clients/rust/marginfi-cli/Cargo.toml @@ -27,6 +27,7 @@ anchor-spl = { workspace = true, features = ["token_2022"] } pyth-sdk-solana = { workspace = true } switchboard-solana = { workspace = true } +switchboard-on-demand = "0.1.14" borsh = "0.10.3" marginfi = { path = "../../../programs/marginfi", version = "0.1.0", features = [ diff --git a/clients/rust/marginfi-cli/src/entrypoint.rs b/clients/rust/marginfi-cli/src/entrypoint.rs index 1956d0d75..9e7a62b42 100644 --- a/clients/rust/marginfi-cli/src/entrypoint.rs +++ b/clients/rust/marginfi-cli/src/entrypoint.rs @@ -80,6 +80,9 @@ pub enum Command { FindPythPull { feed_id: String, }, + InspectSwbPullFeed { + address: Pubkey, + }, } #[derive(Debug, Parser)] @@ -170,16 +173,18 @@ impl From for RiskTier { #[derive(Clone, Copy, Debug, Parser, ArgEnum)] pub enum OracleTypeArg { PythLegacy, - Switchboard, + SwitchboardLegacy, PythPushOracle, + SwitchboardPull, } impl From for OracleSetup { fn from(value: OracleTypeArg) -> Self { match value { OracleTypeArg::PythLegacy => OracleSetup::PythLegacy, - OracleTypeArg::Switchboard => OracleSetup::SwitchboardV2, + OracleTypeArg::SwitchboardLegacy => OracleSetup::SwitchboardV2, OracleTypeArg::PythPushOracle => OracleSetup::PythPushOracle, + OracleTypeArg::SwitchboardPull => OracleSetup::SwitchboardPull, } } } @@ -445,7 +450,7 @@ pub fn entry(opts: Opts) -> Result<()> { let profile = load_profile()?; let config = profile.get_config(Some(&opts.cfg_override))?; - processor::inspect_pyth_push_feed(&config, pyth_feed)?; + processor::oracle::inspect_pyth_push_feed(&config, pyth_feed)?; Ok(()) } @@ -458,6 +463,14 @@ pub fn entry(opts: Opts) -> Result<()> { find_pyth_push_oracles_for_feed_id(&rpc, feed_id)?; + Ok(()) + } + Command::InspectSwbPullFeed { address } => { + let profile = load_profile()?; + let config = profile.get_config(Some(&opts.cfg_override))?; + + processor::oracle::inspect_swb_pull_feed(&config, address)?; + Ok(()) } } diff --git a/clients/rust/marginfi-cli/src/processor/mod.rs b/clients/rust/marginfi-cli/src/processor/mod.rs index e94dde188..061c31326 100644 --- a/clients/rust/marginfi-cli/src/processor/mod.rs +++ b/clients/rust/marginfi-cli/src/processor/mod.rs @@ -20,7 +20,6 @@ use { }, anchor_spl::token_2022::spl_token_2022, anyhow::{anyhow, bail, Result}, - borsh::BorshDeserialize, fixed::types::I80F48, log::info, marginfi::{ @@ -40,7 +39,6 @@ use { utils::NumTraitsWithTolerance, }, pyth_sdk_solana::state::{load_price_account, SolanaPriceAccount}, - pyth_solana_receiver_sdk::price_update::PriceUpdateV2, solana_client::{ rpc_client::RpcClient, rpc_filter::{Memcmp, RpcFilterType}, @@ -2418,23 +2416,3 @@ fn timestamp_to_string(timestamp: i64) -> String { .format("%Y-%m-%d %H:%M:%S") .to_string() } - -pub fn inspect_pyth_push_feed(config: &Config, address: Pubkey) -> anyhow::Result<()> { - let mut account = config.mfi_program.rpc().get_account(&address)?; - let ai = (&address, &mut account).into_account_info(); - - let mut data = &ai.try_borrow_data()?[8..]; - let price_update = PriceUpdateV2::deserialize(&mut data)?; - - println!("Pyth Push Feed: {}", address); - let feed = PythPushOraclePriceFeed::load_unchecked(&ai)?; - - println!( - "Price: {}", - feed.get_price_of_type(marginfi::state::price::OraclePriceType::RealTime, None)? - ); - - println!("Feed id: {:?}", price_update.price_message.feed_id); - - Ok(()) -} diff --git a/clients/rust/marginfi-cli/src/processor/oracle.rs b/clients/rust/marginfi-cli/src/processor/oracle.rs index f3b89e276..03b084820 100644 --- a/clients/rust/marginfi-cli/src/processor/oracle.rs +++ b/clients/rust/marginfi-cli/src/processor/oracle.rs @@ -1,10 +1,20 @@ -use pyth_solana_receiver_sdk::price_update::FeedId; +use crate::config::Config; +use borsh::BorshDeserialize; +use chrono::{DateTime, Local, TimeZone}; +use fixed::types::I80F48; +use marginfi::{ + constants::EXP_10_I80F48, + state::price::{PriceAdapter, PythPushOraclePriceFeed}, +}; +use pyth_solana_receiver_sdk::price_update::{FeedId, PriceUpdateV2}; use solana_account_decoder::UiAccountEncoding; use solana_client::rpc_client::RpcClient; use solana_client::rpc_config::{RpcAccountInfoConfig, RpcProgramAccountsConfig}; use solana_client::rpc_filter::{Memcmp, RpcFilterType}; use solana_sdk::account_info::IntoAccountInfo; +use solana_sdk::pubkey::Pubkey; use std::time::{SystemTime, UNIX_EPOCH}; +use switchboard_on_demand::PullFeedAccountData; pub fn find_pyth_push_oracles_for_feed_id( rpc_client: &RpcClient, @@ -45,3 +55,53 @@ pub fn find_pyth_push_oracles_for_feed_id( Ok(()) } + +pub fn inspect_pyth_push_feed(config: &Config, address: Pubkey) -> anyhow::Result<()> { + let mut account = config.mfi_program.rpc().get_account(&address)?; + let ai = (&address, &mut account).into_account_info(); + + let mut data = &ai.try_borrow_data()?[8..]; + let price_update = PriceUpdateV2::deserialize(&mut data)?; + + println!("Pyth Push Feed: {}", address); + let feed = PythPushOraclePriceFeed::load_unchecked(&ai)?; + + println!( + "Price: {}", + feed.get_price_of_type(marginfi::state::price::OraclePriceType::RealTime, None)? + ); + + let feed_id = price_update.price_message.feed_id; + + println!("Feed id: {:?}", feed_id); + println!("Feed id hex: 0x{}", hex::encode(feed_id)); + + Ok(()) +} + +pub fn inspect_swb_pull_feed(config: &Config, address: Pubkey) -> anyhow::Result<()> { + let mut account = config.mfi_program.rpc().get_account(&address)?; + + let ai = (&address, &mut account).into_account_info(); + let feed = PullFeedAccountData::parse(ai.data.borrow())?; + + let price: I80F48 = I80F48::from_num(feed.result.value) + .checked_div(EXP_10_I80F48[switchboard_on_demand::PRECISION as usize]) + .unwrap(); + + let last_updated = feed.last_update_timestamp; + let current_timestamp = SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs() as i64; + let age = current_timestamp.saturating_sub(last_updated); + let datetime: DateTime = Local.timestamp_opt(last_updated, 0).unwrap(); + + println!("price: {}", price); + println!( + "last updated: {} (ts: {}; slot {})", + datetime, + last_updated, + feed.result.result_slot().unwrap_or(0) + ); + println!("age: {}s", age); + + Ok(()) +} diff --git a/package.json b/package.json index 35b84044c..fdb1184eb 100644 --- a/package.json +++ b/package.json @@ -1,20 +1,26 @@ { - "scripts": { - "lint:fix": "prettier */*.js \"*/**/*{.js,.ts}\" -w", - "lint": "prettier */*.js \"*/**/*{.js,.ts}\" --check" - }, - "dependencies": { - "@project-serum/anchor": "^0.25.0", - "@pythnetwork/client": "^2.9.0" - }, - "devDependencies": { - "@types/bn.js": "^5.1.0", - "@types/chai": "^4.3.0", - "@types/mocha": "^9.0.0", - "chai": "^4.3.4", - "mocha": "^9.0.3", - "prettier": "^2.6.2", - "ts-mocha": "^10.0.0", - "typescript": "^4.3.5" - } + "scripts": { + "lint:fix": "prettier */*.js \"*/**/*{.js,.ts}\" -w", + "lint": "prettier */*.js \"*/**/*{.js,.ts}\" --check" + }, + "dependencies": { + "@coral-xyz/anchor": "^0.30.1", + "@coral-xyz/spl-token": "^0.30.1", + "@solana/spl-token": "^0.4.8", + "@solana/web3.js": "^1.95.2", + "@mrgnlabs/mrgn-common": "^1.7.0", + "@mrgnlabs/marginfi-client-v2": "^3.1.0", + "mocha": "^10.2.0", + "ts-mocha": "^10.0.0", + "bignumber.js": "^9.1.2" + }, + "devDependencies": { + "@types/bn.js": "^5.1.0", + "@types/chai": "^4.3.0", + "@types/mocha": "^9.0.0", + "chai": "^4.3.4", + "prettier": "^2.6.2", + "ts-node": "^10.9.1", + "typescript": "^4.3.5" + } } diff --git a/programs/marginfi/src/constants.rs b/programs/marginfi/src/constants.rs index 360f021d6..e3b67d31f 100644 --- a/programs/marginfi/src/constants.rs +++ b/programs/marginfi/src/constants.rs @@ -21,7 +21,8 @@ cfg_if::cfg_if! { } else if #[cfg(any(feature = "mainnet-beta", feature = "staging"))] { pub const PYTH_ID: Pubkey = pubkey!("FsJ3A3u2vn5cTVofAjvy6y5kwABJAqYWpe4975bi2epH"); } else { - pub const PYTH_ID: Pubkey = pubkey!("5rYvdyWAunZgD2EC1aKo7hQbutUUnkt7bBFM6xNq2z7Z"); + // The key of the mock program on localnet (see its declared id) + pub const PYTH_ID: Pubkey = pubkey!("5XaaR94jBubdbrRrNW7DtRvZeWvLhSHkEGU3jHTEXV3C"); } } diff --git a/programs/marginfi/src/lib.rs b/programs/marginfi/src/lib.rs index f51c0ecc7..d9dbd9f70 100644 --- a/programs/marginfi/src/lib.rs +++ b/programs/marginfi/src/lib.rs @@ -20,7 +20,7 @@ cfg_if::cfg_if! { } else if #[cfg(feature = "staging")] { declare_id!("stag8sTKds2h4KzjUw3zKTsxbqvT4XKHdaR9X9E6Rct"); } else { - declare_id!("Mfi1111111111111111111111111111111111111111"); + declare_id!("2jGhuVUuy3umdzByFx8sNWUAaf5vaeuDm78RDPEnhrMr"); } } diff --git a/programs/marginfi/src/state/marginfi_group.rs b/programs/marginfi/src/state/marginfi_group.rs index 92783487f..ead16d9d7 100644 --- a/programs/marginfi/src/state/marginfi_group.rs +++ b/programs/marginfi/src/state/marginfi_group.rs @@ -295,6 +295,10 @@ pub struct Bank { pub group: Pubkey, + // Note: The padding is here, not after mint_decimals. Pubkey has alignment 1, so those 32 + // bytes can cross the alignment 8 threshold, but WrappedI80F48 has alignment 8 and cannot + pub _pad0: [u8; 7], // 1x u8 + 7 = 8 + pub asset_share_value: WrappedI80F48, pub liability_share_value: WrappedI80F48, @@ -305,11 +309,17 @@ pub struct Bank { pub insurance_vault: Pubkey, pub insurance_vault_bump: u8, pub insurance_vault_authority_bump: u8, + + pub _pad1: [u8; 4], // 4x u8 + 4 = 8 + pub collected_insurance_fees_outstanding: WrappedI80F48, pub fee_vault: Pubkey, pub fee_vault_bump: u8, pub fee_vault_authority_bump: u8, + + pub _pad2: [u8; 6], // 2x u8 + 6 = 8 + pub collected_group_fees_outstanding: WrappedI80F48, pub total_liability_shares: WrappedI80F48, @@ -929,7 +939,7 @@ impl Display for BankOperationalState { } } -#[repr(u64)] +#[repr(u8)] #[derive(Copy, Clone, Debug, AnchorSerialize, AnchorDeserialize, PartialEq, Eq)] pub enum RiskTier { Collateral, @@ -968,6 +978,8 @@ pub struct BankConfigCompact { pub risk_tier: RiskTier, + pub _pad0: [u8; 7], + /// USD denominated limit for calculating asset value for initialization margin requirements. /// Example, if total SOL deposits are equal to $1M and the limit it set to $500K, /// then SOL assets will be discounted by 50%. @@ -1001,11 +1013,13 @@ impl From for BankConfig { operational_state: config.operational_state, oracle_setup: config.oracle_setup, oracle_keys: keys, + _pad0: [0; 6], borrow_limit: config.borrow_limit, risk_tier: config.risk_tier, + _pad1: [0; 7], total_asset_value_init_limit: config.total_asset_value_init_limit, oracle_max_age: config.oracle_max_age, - _padding: [0; 19], + _padding: [0; 38], } } } @@ -1024,6 +1038,7 @@ impl From for BankConfigCompact { oracle_key: config.oracle_keys[0], borrow_limit: config.borrow_limit, risk_tier: config.risk_tier, + _pad0: [0; 7], total_asset_value_init_limit: config.total_asset_value_init_limit, oracle_max_age: config.oracle_max_age, } @@ -1055,10 +1070,15 @@ pub struct BankConfig { pub oracle_setup: OracleSetup, pub oracle_keys: [Pubkey; MAX_ORACLE_KEYS], + // Note: Pubkey is aligned 1, so borrow_limit is the first aligned-8 value after deposit_limit + pub _pad0: [u8; 6], // Bank state (1) + Oracle Setup (1) + 6 = 8 + pub borrow_limit: u64, pub risk_tier: RiskTier, + pub _pad1: [u8; 7], + /// USD denominated limit for calculating asset value for initialization margin requirements. /// Example, if total SOL deposits are equal to $1M and the limit it set to $500K, /// then SOL assets will be discounted by 50%. @@ -1072,7 +1092,7 @@ pub struct BankConfig { /// Time window in seconds for the oracle price feed to be considered live. pub oracle_max_age: u16, - pub _padding: [u16; 19], // 16 * 4 = 64 bytes + pub _padding: [u8; 38], } impl Default for BankConfig { @@ -1088,10 +1108,12 @@ impl Default for BankConfig { operational_state: BankOperationalState::Paused, oracle_setup: OracleSetup::None, oracle_keys: [Pubkey::default(); MAX_ORACLE_KEYS], + _pad0: [0; 6], risk_tier: RiskTier::Isolated, + _pad1: [0; 7], total_asset_value_init_limit: TOTAL_ASSET_VALUE_INIT_LIMIT_INACTIVE, oracle_max_age: 0, - _padding: [0; 19], + _padding: [0; 38], } } } diff --git a/programs/marginfi/tests/admin_actions/setup_bank.rs b/programs/marginfi/tests/admin_actions/setup_bank.rs index 5a5555388..2d7eade8a 100644 --- a/programs/marginfi/tests/admin_actions/setup_bank.rs +++ b/programs/marginfi/tests/admin_actions/setup_bank.rs @@ -72,6 +72,7 @@ async fn add_bank_success() -> anyhow::Result<()> { emissions_mint, _padding_0, _padding_1, + .. // ignore internal padding } = bank_f.load().await; #[rustfmt::skip] let _ = { @@ -174,6 +175,7 @@ async fn add_bank_with_seed_success() -> anyhow::Result<()> { emissions_mint, _padding_0, _padding_1, + .. // ignore internal padding } = bank_f.load().await; #[rustfmt::skip] let _ = { diff --git a/programs/marginfi/tests/fixtures/bank/bank_pyusd_230822.json b/programs/marginfi/tests/fixtures/bank/bank_pyusd_230822.json new file mode 100644 index 000000000..3ab9e482d --- /dev/null +++ b/programs/marginfi/tests/fixtures/bank/bank_pyusd_230822.json @@ -0,0 +1,14 @@ +{ + "pubkey": "8UEiPmgZHXXEDrqLS3oiTxQxTbeYTtPbeMBxAd2XGbpu", + "account": { + "lamports": 13864320, + "data": [ + "jjGm8jJCYbwXkkg7bIoqh7dHHYFPlZH5OVyECpzj2fTVun06S4p0ngY5FC9oL9g4hJbsvVEG8Vx5TCR3Qzgo+mZC2+v3IANKYQAAAAAAAACibHm/BQABAAAAAAAAAAAAWLyUcWcAAQAAAAAAAAAAAPTXvfK6z6svhbXWDfTOr3olZx7OmKfKqIafQ/kPPiJu+f83ZEO178ClXtlqcK24JUSCeqEA6uSI3AL1GNNmaP34ff/+AAAAAIOly76Ug4MNAAAAAAAAAACUc8uy2ZCNgFnDRd1BWM/oqjuaLwvhpWZmB5eoAZsWmf/9AAAAAAAAVy1QjSqN+k6KPAAAAAAAAKrxZSvYs7NKmgbRAQAAAAAQ+cJH1DbWP7NoYCQAAAAAsMPGZgAAAAAAAABmZuYAAAAAAAAAAAAAAAAAMzPzAAAAAAAAAAAAAAAAAAAAQAEAAAAAAAAAAACamZmZmRkBAAAAAAAAAAAAAIDKOWEkAADNzMzMzMwAAAAAAAAAAAAAmpmZmZkZAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMP1KFyPAgAAAAAAAAAAAADNzMzMzAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABA8HaG3PX8B593VSzdmz3/NZEOVrRT3CqcG7FOExZ52aSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEqp0QEAAAAAAAAAAAAAAAAAAAAAAAAsAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAQmAIAAAAAAAA7mF+QrK2Sg2ceAAAAAAAXkkg7bIoqh7dHHYFPlZH5OVyECpzj2fTVun06S4p0ngAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==", + "base64" + ], + "owner": "MFv2hWf31Z9kbCa1snEPYctwafyhdvnV7FZnsebVacA", + "executable": false, + "rentEpoch": 18446744073709551615, + "space": 1864 + } +} \ No newline at end of file diff --git a/programs/marginfi/tests/misc/regression.rs b/programs/marginfi/tests/misc/regression.rs index 7fae0d7d6..8d27d39ec 100644 --- a/programs/marginfi/tests/misc/regression.rs +++ b/programs/marginfi/tests/misc/regression.rs @@ -4,11 +4,16 @@ use anchor_lang::AccountDeserialize; use anyhow::bail; use base64::{prelude::BASE64_STANDARD, Engine}; use fixed::types::I80F48; -use marginfi::state::{marginfi_account::MarginfiAccount, marginfi_group::Bank}; +use marginfi::state::{ + marginfi_account::MarginfiAccount, + marginfi_group::{Bank, BankOperationalState, RiskTier}, + price::OracleSetup, +}; use solana_account_decoder::UiAccountData; use solana_cli_output::CliAccount; use solana_program::pubkey; use solana_program_test::tokio; +use switchboard_solana::Pubkey; #[tokio::test] async fn account_field_values_reg() -> anyhow::Result<()> { @@ -429,5 +434,161 @@ async fn bank_field_values_reg() -> anyhow::Result<()> { I80F48::from_str("0.05").unwrap() ); + // Sample 4 (PyUSD) + + let mut path = PathBuf::from_str(bank_fixtures_path).unwrap(); + path.push("bank_pyusd_230822.json"); + let mut file = File::open(&path).unwrap(); + let mut account_info_raw = String::new(); + file.read_to_string(&mut account_info_raw).unwrap(); + + let account: CliAccount = serde_json::from_str(&account_info_raw).unwrap(); + let UiAccountData::Binary(data, _) = account.keyed_account.account.data else { + bail!("Expecting Binary format for fixtures") + }; + let bank = Bank::try_deserialize(&mut BASE64_STANDARD.decode(data)?.as_slice())?; + + assert_eq!( + bank.mint, + pubkey!("2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo") + ); + assert_eq!(bank.mint_decimals, 6); + assert_eq!( + bank.group, + pubkey!("4qp6Fx6tnZkY5Wropq9wUYgtFxXKwE6viZxFHg3rdAG8") + ); + assert_eq!(bank._pad0, [0; 7]); + assert_eq!( + I80F48::from(bank.asset_share_value), + I80F48::from_str("1.000087706703773").unwrap() + ); + assert_eq!( + I80F48::from(bank.liability_share_value), + I80F48::from_str("1.00157842522853").unwrap() + ); + assert_eq!( + bank.liquidity_vault, + pubkey!("HUmHLAXvcoUgWAtanAnCPNssBnAUzEfSRsb4MZYw7R73") + ); + assert_eq!(bank.liquidity_vault_bump, 249); + assert_eq!(bank.liquidity_vault_authority_bump, 255); + assert_eq!( + bank.insurance_vault, + pubkey!("4jE6g1pLG5NmW19z9DgzjCwYEDy3jYSqix1Lv5BN4yEc") + ); + assert_eq!(bank.insurance_vault_bump, 255); + assert_eq!(bank.insurance_vault_authority_bump, 254); + assert_eq!(bank._pad1, [0; 4]); + assert_eq!( + I80F48::from(bank.collected_insurance_fees_outstanding), + I80F48::from_str("3459.51398842307891").unwrap() + ); + assert_eq!( + bank.fee_vault, + pubkey!("AzVkUZFuvGwy3pD6U2eAJJNhHYMnzkzBFjjhn8CSVFRa") + ); + assert_eq!(bank.fee_vault_bump, 255); + assert_eq!(bank.fee_vault_authority_bump, 253); + assert_eq!(bank._pad2, [0; 6]); + assert_eq!( + I80F48::from(bank.collected_group_fees_outstanding), + I80F48::from_str("1015697146.551430542063226").unwrap() + ); + assert_eq!( + I80F48::from(bank.total_liability_shares), + I80F48::from_str("1997270567603.702517235172913").unwrap() + ); + assert_eq!( + I80F48::from(bank.total_asset_shares), + I80F48::from_str("39996492038102.214176640606695").unwrap() + ); + assert_eq!(bank.last_update, 1724302256); + + assert_eq!( + I80F48::from(bank.config.asset_weight_init), + I80F48::from_str("0.899999976158142").unwrap() + ); + assert_eq!( + I80F48::from(bank.config.asset_weight_maint), + I80F48::from_str("0.94999998807907").unwrap() + ); + assert_eq!( + I80F48::from(bank.config.liability_weight_init), + I80F48::from_str("1.25").unwrap() + ); + assert_eq!( + I80F48::from(bank.config.liability_weight_maint), + I80F48::from_str("1.1").unwrap() + ); + assert_eq!(bank.config.deposit_limit, 40000000000000); + assert_eq!( + I80F48::from(bank.config.interest_rate_config.optimal_utilization_rate), + I80F48::from_str("0.8").unwrap() + ); + assert_eq!( + I80F48::from(bank.config.interest_rate_config.plateau_interest_rate), + I80F48::from_str("0.1").unwrap() + ); + assert_eq!( + I80F48::from(bank.config.interest_rate_config.max_interest_rate), + I80F48::from_str("3").unwrap() + ); + assert_eq!( + I80F48::from(bank.config.interest_rate_config.insurance_fee_fixed_apr), + I80F48::from_str("0").unwrap() + ); + assert_eq!( + I80F48::from(bank.config.interest_rate_config.insurance_ir_fee), + I80F48::from_str("0").unwrap() + ); + assert_eq!( + I80F48::from(bank.config.interest_rate_config.protocol_fixed_fee_apr), + I80F48::from_str("0.01").unwrap() + ); + assert_eq!( + I80F48::from(bank.config.interest_rate_config.protocol_ir_fee), + I80F48::from_str("0.05").unwrap() + ); + assert_eq!( + bank.config.operational_state, + BankOperationalState::Operational + ); + assert_eq!(bank.config.oracle_setup, OracleSetup::PythPushOracle); + assert_eq!( + bank.config.oracle_keys, + [ + pubkey!("E3iagrg2kXyNJ9Ad2R2pNUsRmXutyQScu3m1FcQmBsAH"), + Pubkey::default(), + Pubkey::default(), + Pubkey::default(), + Pubkey::default() + ] + ); + assert_eq!(bank.config._pad0, [0; 6]); + assert_eq!(bank.config.borrow_limit, 2000000000000); + assert_eq!(bank.config.risk_tier, RiskTier::Collateral); + assert_eq!(bank.config._pad1, [0; 7]); + assert_eq!(bank.config.total_asset_value_init_limit, 0); + assert_eq!(bank.config.oracle_max_age, 300); + assert_eq!(bank.config._padding, [0; 38]); + + assert_eq!(bank.flags, 2); + + assert_eq!( + I80F48::from(bank.emissions_rate), + I80F48::from_str("170000").unwrap() + ); + assert_eq!( + I80F48::from(bank.emissions_remaining), + I80F48::from_str("130585694893.67407796351017").unwrap() + ); + assert_eq!( + bank.emissions_mint, + pubkey!("2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo") + ); + + assert_eq!(bank._padding_0, [[0, 0]; 28]); + assert_eq!(bank._padding_1, [[0, 0]; 32]); + Ok(()) } diff --git a/programs/mocks/Cargo.toml b/programs/mocks/Cargo.toml new file mode 100644 index 000000000..e1a5ff097 --- /dev/null +++ b/programs/mocks/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "mocks" +version = "0.1.0" +description = "External program mocks" +edition = "2021" + +[lib] +crate-type = ["cdylib", "lib"] +name = "mocks" + +[features] +no-entrypoint = [] +no-idl = [] +no-log-ix-name = [] +cpi = ["no-entrypoint"] +default = ["mainnet-beta"] +idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"] +test-bpf = ["test", "debug"] +test = [] +client = [] +devnet = [] +mainnet-beta = [] +debug = [] +staging = [] + +[dependencies] +anchor-lang = { workspace = true } +anchor-spl = { workspace = true } + +bytemuck = { version = "1.9.1", features = ["derive"] } +static_assertions = "1.1.0" \ No newline at end of file diff --git a/programs/mocks/src/errors.rs b/programs/mocks/src/errors.rs new file mode 100644 index 000000000..5f5b7b38c --- /dev/null +++ b/programs/mocks/src/errors.rs @@ -0,0 +1,7 @@ +use anchor_lang::error_code; + +#[error_code] +pub enum ErrorCode { + #[msg("This is an error.")] + SomeError, // 6000 +} diff --git a/programs/mocks/src/instructions/do_nothing.rs b/programs/mocks/src/instructions/do_nothing.rs new file mode 100644 index 000000000..76a6d2b46 --- /dev/null +++ b/programs/mocks/src/instructions/do_nothing.rs @@ -0,0 +1,14 @@ +use anchor_lang::prelude::*; + +#[derive(Accounts)] +pub struct DoNothing<'info> { + pub payer: Signer<'info>, +} + +pub fn do_nothing(ctx: Context) -> Result<()> { + msg!( + "Nothing was done. Signed by: {:?}", + ctx.accounts.payer.key() + ); + Ok(()) +} diff --git a/programs/mocks/src/instructions/init_pool_auth.rs b/programs/mocks/src/instructions/init_pool_auth.rs new file mode 100644 index 000000000..11cdf96cf --- /dev/null +++ b/programs/mocks/src/instructions/init_pool_auth.rs @@ -0,0 +1,71 @@ +use anchor_lang::prelude::*; +use anchor_spl::token::{Mint, Token, TokenAccount}; + +use crate::state::PoolAuth; + +#[derive(Accounts)] +#[instruction( + nonce: u16, +)] +pub struct InitPoolAuth<'info> { + /// Pays the init fee + #[account(mut)] + pub payer: Signer<'info>, + + #[account( + init, + seeds = [ + &nonce.to_le_bytes(), + b"pool_auth".as_ref(), + ], + bump, + payer = payer, + space = 8 + PoolAuth::LEN, + )] + pub pool_auth: Account<'info, PoolAuth>, + + pub mint_a: Account<'info, Mint>, + pub mint_b: Account<'info, Mint>, + + #[account( + init, + seeds = [ + mint_a.key().as_ref(), + pool_auth.key().as_ref(), + b"pools", + ], + bump, + token::mint = mint_a, + token::authority = pool_auth, + payer = payer + )] + pub pool_a: Account<'info, TokenAccount>, + + #[account( + init, + seeds = [ + mint_b.key().as_ref(), + pool_auth.key().as_ref(), + b"pools", + ], + bump, + token::mint = mint_b, + token::authority = pool_auth, + payer = payer + )] + pub pool_b: Account<'info, TokenAccount>, + + pub token_program: Program<'info, Token>, + pub rent: Sysvar<'info, Rent>, + pub system_program: Program<'info, System>, +} + +pub fn init_pool_auth(ctx: Context, nonce: u16) -> Result<()> { + let pool_auth = &mut ctx.accounts.pool_auth; + pool_auth.nonce = nonce; + pool_auth.pool_a = ctx.accounts.pool_a.key(); + pool_auth.pool_b = ctx.accounts.pool_b.key(); + pool_auth.bump_seed = ctx.bumps.pool_auth; + + Ok(()) +} diff --git a/programs/mocks/src/instructions/mod.rs b/programs/mocks/src/instructions/mod.rs new file mode 100644 index 000000000..e98adaaf6 --- /dev/null +++ b/programs/mocks/src/instructions/mod.rs @@ -0,0 +1,7 @@ +pub mod do_nothing; +pub mod init_pool_auth; +pub mod swap_like_jupiter; + +pub use do_nothing::*; +pub use init_pool_auth::*; +pub use swap_like_jupiter::*; diff --git a/programs/mocks/src/instructions/swap_like_jupiter.rs b/programs/mocks/src/instructions/swap_like_jupiter.rs new file mode 100644 index 000000000..0c5b17818 --- /dev/null +++ b/programs/mocks/src/instructions/swap_like_jupiter.rs @@ -0,0 +1,75 @@ +use anchor_lang::prelude::*; +use anchor_spl::token::{self, Token, TokenAccount, Transfer}; + +use crate::{pool_auth_signer_seeds, state::PoolAuth}; + +#[derive(Accounts)] +pub struct SwapLikeJupiter<'info> { + pub user_authority: Signer<'info>, + + /// PDA authority of the pools + /// CHECK: this is a mock program, security doesn't matter + pub pool_auth: Account<'info, PoolAuth>, + + #[account(mut)] + pub pool_a: Account<'info, TokenAccount>, + + #[account(mut)] + pub pool_b: Account<'info, TokenAccount>, + + #[account(mut)] + pub source_a: Account<'info, TokenAccount>, + + #[account(mut)] + pub destination_b: Account<'info, TokenAccount>, + + pub token_program: Program<'info, Token>, +} + +impl<'info> SwapLikeJupiter<'info> { + pub fn swap_like_jup( + ctx: Context<'_, '_, '_, 'info, SwapLikeJupiter<'info>>, + amt_a: u64, + amt_b: u64, + ) -> Result<()> { + let pool_auth = &ctx.accounts.pool_auth; + + let a_before = ctx.accounts.source_a.amount; + msg!("User a before: {:?} transfer {:?}", a_before, amt_a); + token::transfer(ctx.accounts.transfer_a_to_pool(), amt_a)?; + + let b_before = ctx.accounts.pool_b.amount; + msg!("Pool b before: {:?} transfer {:?}", b_before, amt_b); + token::transfer( + ctx.accounts + .transfer_b_to_user() + .with_signer(&[pool_auth_signer_seeds!(pool_auth)]), + amt_b, + )?; + + Ok(()) + } +} + +impl<'info> SwapLikeJupiter<'info> { + fn transfer_a_to_pool(&self) -> CpiContext<'_, '_, '_, 'info, Transfer<'info>> { + CpiContext::new( + self.token_program.to_account_info(), + Transfer { + from: self.source_a.to_account_info(), + to: self.pool_a.to_account_info(), + authority: self.user_authority.to_account_info(), + }, + ) + } + fn transfer_b_to_user(&self) -> CpiContext<'_, '_, '_, 'info, Transfer<'info>> { + CpiContext::new( + self.token_program.to_account_info(), + Transfer { + from: self.pool_b.to_account_info(), + to: self.destination_b.to_account_info(), + authority: self.pool_auth.to_account_info(), + }, + ) + } +} diff --git a/programs/mocks/src/lib.rs b/programs/mocks/src/lib.rs new file mode 100644 index 000000000..026cf9f23 --- /dev/null +++ b/programs/mocks/src/lib.rs @@ -0,0 +1,53 @@ +use anchor_lang::prelude::*; + +pub mod errors; +pub mod instructions; +pub mod macros; +pub mod state; +// pub mod utils; + +use crate::instructions::*; +// use crate::state::*; +// use errors::*; + +declare_id!("5XaaR94jBubdbrRrNW7DtRvZeWvLhSHkEGU3jHTEXV3C"); + +#[program] +pub mod mocks { + use super::*; + use std::io::Write as IoWrite; + + /// Do nothing + pub fn do_nothing(ctx: Context) -> Result<()> { + instructions::do_nothing::do_nothing(ctx) + } + + /// Init authority for fake jupiter-like swap pools + pub fn init_pool_auth(ctx: Context, nonce: u16) -> Result<()> { + instructions::init_pool_auth::init_pool_auth(ctx, nonce) + } + + /// Execute an exchange of a:b like-jupiter. You set the amount a sent and b received. + pub fn swap_like_jupiter<'info>( + ctx: Context<'_, '_, '_, 'info, SwapLikeJupiter<'info>>, + amt_a: u64, + amt_b: u64, + ) -> Result<()> { + instructions::swap_like_jupiter::SwapLikeJupiter::swap_like_jup(ctx, amt_a, amt_b) + } + + #[derive(Accounts)] + pub struct Write<'info> { + #[account(mut)] + target: Signer<'info>, + } + + /// Write arbitrary bytes to an arbitrary account. YOLO. + pub fn write(ctx: Context, offset: u64, data: Vec) -> Result<()> { + let account_data = ctx.accounts.target.to_account_info().data; + let borrow_data = &mut *account_data.borrow_mut(); + let offset = offset as usize; + + Ok((&mut borrow_data[offset..]).write_all(&data[..])?) + } +} diff --git a/programs/mocks/src/macros.rs b/programs/mocks/src/macros.rs new file mode 100644 index 000000000..c9db378d1 --- /dev/null +++ b/programs/mocks/src/macros.rs @@ -0,0 +1,10 @@ +#[macro_export] +macro_rules! pool_auth_signer_seeds { + ($pool_auth:expr) => { + &[ + &$pool_auth.nonce.to_le_bytes(), + b"pool_auth".as_ref(), + &[$pool_auth.bump_seed], + ] + }; +} diff --git a/programs/mocks/src/state/mod.rs b/programs/mocks/src/state/mod.rs new file mode 100644 index 000000000..e3077eccc --- /dev/null +++ b/programs/mocks/src/state/mod.rs @@ -0,0 +1,3 @@ +pub mod pool_auth; + +pub use pool_auth::*; diff --git a/programs/mocks/src/state/pool_auth.rs b/programs/mocks/src/state/pool_auth.rs new file mode 100644 index 000000000..634abcaf7 --- /dev/null +++ b/programs/mocks/src/state/pool_auth.rs @@ -0,0 +1,15 @@ +use anchor_lang::prelude::*; + +#[account()] +pub struct PoolAuth { + /// The account's own key + pub key: Pubkey, + pub pool_a: Pubkey, + pub pool_b: Pubkey, + pub bump_seed: u8, + pub nonce: u16, +} + +impl PoolAuth { + pub const LEN: usize = std::mem::size_of::(); +} diff --git a/scripts/build-program-verifiable.sh b/scripts/build-program-verifiable.sh index 5ea69ea65..25d86c12d 100755 --- a/scripts/build-program-verifiable.sh +++ b/scripts/build-program-verifiable.sh @@ -19,9 +19,9 @@ fi if [ "$deployment" = "mainnet" ]; then features="--features mainnet-beta" elif [ "$deployment" = "devnet" ]; then - features="--features devnet" + features="--features devnet --no-default-features" elif [ "$deployment" = "staging" ]; then - features="--features staging" + features="--features staging --no-default-features" else echo "Error: Unknown deployment: $deployment" exit 1 diff --git a/scripts/build-program.sh b/scripts/build-program.sh index 0769f2896..1ca3556f1 100755 --- a/scripts/build-program.sh +++ b/scripts/build-program.sh @@ -11,14 +11,16 @@ if [ -z "$program_lib_name" ] || [ -z "$cluster" ]; then fi if [ "$cluster" = "mainnet" ]; then - cluster_feature="mainnet-beta" + features="--features mainnet-beta" elif [ "$cluster" = "devnet" ]; then - cluster_feature=" devnet" + features="--features devnet --no-default-features" +elif [ "$cluster" = "staging" ]; then + features="--features staging --no-default-features" else echo "Error: Unknown cluster: $cluster" exit 1 fi -cmd="anchor build -p $program_lib_name -- --features $cluster_feature" +cmd="anchor build -p $program_lib_name -- $features" echo "Running: $cmd" eval "$cmd" diff --git a/scripts/deploy-buffer.sh b/scripts/deploy-buffer.sh index 2087f9bd2..74c4e1373 100755 --- a/scripts/deploy-buffer.sh +++ b/scripts/deploy-buffer.sh @@ -3,23 +3,14 @@ ROOT=$(git rev-parse --show-toplevel) cd $ROOT program_lib_name=$1 -cluster=$2 +rpc_url=$2 keypair=$3 -if [ -z "$keypair" ] || [ -z "$program_lib_name" ] || [ -z "$cluster" ]; then - echo "Usage: $0 " +if [ -z "$program_lib_name" ] || [ -z "$rpc_url" ] || [ -z "$keypair" ]; then + echo "Usage: $0 " exit 1 fi -if [ "$cluster" = "mainnet" ]; then - url_moniker="https://api.mainnet-beta.solana.com" -elif [ "$cluster" = "devnet" ]; then - url_moniker="https://api.devnet.solana.com" -else - echo "Error: Unknown cluster: $cluster" - exit 1 -fi - -cmd="solana --url $url_moniker program write-buffer "$ROOT/target/deploy/$program_lib_name.so" -k $keypair" +cmd="solana --url $rpc_url program write-buffer "$ROOT/target/deploy/$program_lib_name.so" -k $keypair" echo "Running: $cmd" eval "$cmd" diff --git a/scripts/deploy-staging-program.sh b/scripts/deploy-staging-program.sh index c1cc452fd..581f5c67b 100644 --- a/scripts/deploy-staging-program.sh +++ b/scripts/deploy-staging-program.sh @@ -23,6 +23,9 @@ deployer_key_path=$1 program_address_or_keypair=$2 [ -z "$program_address_or_keypair" ] && echo "Missing program_address_or_keypair argument" && exit 1 +rpc_url=$3 +[ -z "$rpc_url" ] && echo "Missing rpc_url argument" && exit 1 + deployer_pk=$(solana-keygen pubkey $deployer_key_path) deployer_balance=$(solana balance $deployer_key_path) set +e @@ -69,7 +72,7 @@ fi solana program deploy \ --use-rpc \ - --url $url \ + --url $rpc_url \ --fee-payer $deployer_key_path \ --keypair $deployer_key_path \ --program-id $program_address_or_keypair \ diff --git a/test-utils/data/DeyH7QxWvnbbaVB4zFrf4hoq7Q8z1ZT14co42BGwGtfM.bin b/test-utils/data/DeyH7QxWvnbbaVB4zFrf4hoq7Q8z1ZT14co42BGwGtfM.bin new file mode 100644 index 0000000000000000000000000000000000000000..f3994731cabbc290af92d0029e95147013af10b9 GIT binary patch literal 1864 zcmeA(T=vPxDRIvp_M>?TYi;eti<@2@3+dk_e_7}6gi}nLpPygY`uAM%3|31K{S5sZ z7A@1>>g_UrEo%wCBM5WxPn#DbH75z1p=2)H!MOPCqKk9nGt ze?ucTsh#Js-_&~^I=@A_zD@T{{hV8K(qgt)$@V{gnF<#b+g&u**En|Ob^m{kmu0a! zjb+u{UaN!N>fSay!1w<@$nb9-@8g;t$ZcST+LYdMt!iQT3~7@^_IH1;@K0EoCjRjA z(yg<5mWgY$ahIB!WbDCzomY(k~vw^hUEpXZW#JN;g^rFu+kXe7KI@oW! zd@9(t-)*4@(An~Dj-)}YU|?u~vp|frv}Gv#GiQ7d{shXH7#kz=yJ9O`lNryR0Re{DEdMG8b)7RIFM2FJqFH>&UEg+8F0 literal 0 HcmV?d00001 diff --git a/test-utils/data/H6ARHf6YXhGYeQfUzQNGk6rDNnLBQKrenN712K4AQJEG.bin b/test-utils/data/pyth_legacy_sol_price.bin similarity index 100% rename from test-utils/data/H6ARHf6YXhGYeQfUzQNGk6rDNnLBQKrenN712K4AQJEG.bin rename to test-utils/data/pyth_legacy_sol_price.bin diff --git a/test-utils/data/Gnt27xtC473ZT2Mw5u8wZ68Z3gULkSTb5DuxJy7eJotD.bin b/test-utils/data/pyth_legacy_usdc_price.bin similarity index 100% rename from test-utils/data/Gnt27xtC473ZT2Mw5u8wZ68Z3gULkSTb5DuxJy7eJotD.bin rename to test-utils/data/pyth_legacy_usdc_price.bin diff --git a/test-utils/data/7UVimffxr9ow1uXYxsr4LHAcV58mLzhmwaeKvJ1pjLiE.bin b/test-utils/data/pyth_push_sol_price.bin similarity index 100% rename from test-utils/data/7UVimffxr9ow1uXYxsr4LHAcV58mLzhmwaeKvJ1pjLiE.bin rename to test-utils/data/pyth_push_sol_price.bin diff --git a/test-utils/data/BSzfJs4d1tAkSDqkepnfzEVcx2WtDVnwwXa2giy9PLeP.bin b/test-utils/data/swb_pull_sol_price.bin similarity index 100% rename from test-utils/data/BSzfJs4d1tAkSDqkepnfzEVcx2WtDVnwwXa2giy9PLeP.bin rename to test-utils/data/swb_pull_sol_price.bin diff --git a/test-utils/src/test.rs b/test-utils/src/test.rs index f8e53db72..d457afde9 100644 --- a/test-utils/src/test.rs +++ b/test-utils/src/test.rs @@ -513,19 +513,19 @@ impl TestFixture { program.add_account( PYTH_SOL_REAL_FEED, create_pyth_legacy_price_account_from_bytes( - include_bytes!("../data/H6ARHf6YXhGYeQfUzQNGk6rDNnLBQKrenN712K4AQJEG.bin").to_vec(), + include_bytes!("../data/pyth_legacy_sol_price.bin").to_vec(), ), ); program.add_account( PYTH_USDC_REAL_FEED, create_pyth_legacy_price_account_from_bytes( - include_bytes!("../data/Gnt27xtC473ZT2Mw5u8wZ68Z3gULkSTb5DuxJy7eJotD.bin").to_vec(), + include_bytes!("../data/pyth_legacy_usdc_price.bin").to_vec(), ), ); program.add_account( PYTH_PUSH_SOL_REAL_FEED, create_pyth_push_oracle_account_from_bytes( - include_bytes!("../data/7UVimffxr9ow1uXYxsr4LHAcV58mLzhmwaeKvJ1pjLiE.bin").to_vec(), + include_bytes!("../data/pyth_push_sol_price.bin").to_vec(), ), ); @@ -534,7 +534,7 @@ impl TestFixture { program.add_account( SWITCH_PULL_SOL_REAL_FEED, create_switch_pull_oracle_account_from_bytes( - include_bytes!("../data/BSzfJs4d1tAkSDqkepnfzEVcx2WtDVnwwXa2giy9PLeP.bin").to_vec(), + include_bytes!("../data/swb_pull_sol_price.bin").to_vec(), ), ); diff --git a/tests/01_initGroup.spec.ts b/tests/01_initGroup.spec.ts new file mode 100644 index 000000000..03a90dcdc --- /dev/null +++ b/tests/01_initGroup.spec.ts @@ -0,0 +1,33 @@ +import { + Program, + workspace, +} from "@coral-xyz/anchor"; +import { Transaction } from "@solana/web3.js"; +import { groupInitialize } from "./utils/instructions"; +import { Marginfi } from "../target/types/marginfi"; +import { groupAdmin, marginfiGroup } from "./rootHooks"; +import { assertKeysEqual } from "./utils/genericTests"; + +describe("Init group", () => { + const program = workspace.Marginfi as Program; + + it("(admin) Init group - happy path", async () => { + let tx = new Transaction(); + + tx.add( + await groupInitialize(program, { + marginfiGroup: marginfiGroup.publicKey, + admin: groupAdmin.wallet.publicKey, + }) + ); + + await groupAdmin.userMarginProgram.provider.sendAndConfirm(tx, [ + marginfiGroup, + ]); + + let group = await program.account.marginfiGroup.fetch( + marginfiGroup.publicKey + ); + assertKeysEqual(group.admin, groupAdmin.wallet.publicKey); + }); +}); diff --git a/tests/02_configGroup.spec.ts b/tests/02_configGroup.spec.ts new file mode 100644 index 000000000..6c90eb400 --- /dev/null +++ b/tests/02_configGroup.spec.ts @@ -0,0 +1,68 @@ +import { + AnchorProvider, + getProvider, + Program, + Wallet, + workspace, +} from "@coral-xyz/anchor"; +import { Keypair, Transaction } from "@solana/web3.js"; +import { groupConfigure } from "./utils/instructions"; +import { Marginfi } from "../target/types/marginfi"; +import { groupAdmin, marginfiGroup } from "./rootHooks"; +import { assertKeysEqual } from "./utils/genericTests"; + +describe("Config group", () => { + const program = workspace.Marginfi as Program; + + it("(admin) Config group - no change", async () => { + await groupAdmin.userMarginProgram!.provider.sendAndConfirm!( + new Transaction().add( + await groupConfigure(program, { + newAdmin: null, + marginfiGroup: marginfiGroup.publicKey, + admin: groupAdmin.wallet.publicKey, + }) + ) + ); + + let group = await program.account.marginfiGroup.fetch( + marginfiGroup.publicKey + ); + assertKeysEqual(group.admin, groupAdmin.wallet.publicKey); + }); + + it("(admin) Config group - set new admin", async () => { + let newAdmin = Keypair.generate(); + await groupAdmin.userMarginProgram!.provider.sendAndConfirm!( + new Transaction().add( + await groupConfigure(program, { + newAdmin: newAdmin.publicKey, + marginfiGroup: marginfiGroup.publicKey, + admin: groupAdmin.wallet.publicKey, + }) + ) + ); + + let group = await program.account.marginfiGroup.fetch( + marginfiGroup.publicKey + ); + assertKeysEqual(group.admin, newAdmin.publicKey); + + // Restore original + await groupAdmin.userMarginProgram!.provider.sendAndConfirm!( + new Transaction().add( + await groupConfigure(program, { + newAdmin: groupAdmin.wallet.publicKey, + marginfiGroup: marginfiGroup.publicKey, + admin: newAdmin.publicKey, + }) + ), + [newAdmin] + ); + + group = await program.account.marginfiGroup.fetch( + marginfiGroup.publicKey + ); + assertKeysEqual(group.admin, groupAdmin.wallet.publicKey); + }); +}); diff --git a/tests/03_addBank.spec.ts b/tests/03_addBank.spec.ts new file mode 100644 index 000000000..d5597b6b0 --- /dev/null +++ b/tests/03_addBank.spec.ts @@ -0,0 +1,293 @@ +import { BN, Program, workspace } from "@coral-xyz/anchor"; +import { PublicKey, Transaction } from "@solana/web3.js"; +import { addBank } from "./utils/instructions"; +import { Marginfi } from "../target/types/marginfi"; +import { + bankKeypairA, + bankKeypairUsdc, + ecosystem, + groupAdmin, + marginfiGroup, + oracles, + verbose, +} from "./rootHooks"; +import { + assertBNEqual, + assertI80F48Approx, + assertI80F48Equal, + assertKeyDefault, + assertKeysEqual, +} from "./utils/genericTests"; +import { defaultBankConfig } from "./utils/types"; +import { + deriveLiquidityVaultAuthority, + deriveLiquidityVault, + deriveInsuranceVaultAuthority, + deriveInsuranceVault, + deriveFeeVaultAuthority, + deriveFeeVault, +} from "./utils/pdas"; +import { assert } from "chai"; +import { printBufferGroups } from "./utils/tools"; + +describe("Lending pool add bank (add bank to group)", () => { + const program = workspace.Marginfi as Program; + + it("(admin) Add bank (USDC) - happy path", async () => { + let setConfig = defaultBankConfig(oracles.usdcOracle.publicKey); + let bankKey = bankKeypairUsdc.publicKey; + const now = Date.now() / 1000; + + await groupAdmin.userMarginProgram!.provider.sendAndConfirm!( + new Transaction().add( + await addBank(program, { + marginfiGroup: marginfiGroup.publicKey, + admin: groupAdmin.wallet.publicKey, + feePayer: groupAdmin.wallet.publicKey, + bankMint: ecosystem.usdcMint.publicKey, + bank: bankKey, + config: setConfig, + }) + ), + [bankKeypairUsdc] + ); + + if (verbose) { + console.log("*init USDC bank " + bankKey); + } + + let bankData = ( + await program.provider.connection.getAccountInfo(bankKey) + ).data.subarray(8); + printBufferGroups(bankData, 16, 896); + + const bank = await program.account.bank.fetch(bankKey); + const config = bank.config; + const interest = config.interestRateConfig; + const id = program.programId; + + assertKeysEqual(bank.mint, ecosystem.usdcMint.publicKey); + assert.equal(bank.mintDecimals, ecosystem.usdcDecimals); + assertKeysEqual(bank.group, marginfiGroup.publicKey); + + // Keys and bumps... + assertKeysEqual(config.oracleKeys[0], oracles.usdcOracle.publicKey); + + const [_liqAuth, liqAuthBump] = deriveLiquidityVaultAuthority(id, bankKey); + const [liquidityVault, liqVaultBump] = deriveLiquidityVault(id, bankKey); + assertKeysEqual(bank.liquidityVault, liquidityVault); + assert.equal(bank.liquidityVaultBump, liqVaultBump); + assert.equal(bank.liquidityVaultAuthorityBump, liqAuthBump); + + const [_insAuth, insAuthBump] = deriveInsuranceVaultAuthority(id, bankKey); + const [insuranceVault, insurVaultBump] = deriveInsuranceVault(id, bankKey); + assertKeysEqual(bank.insuranceVault, insuranceVault); + assert.equal(bank.insuranceVaultBump, insurVaultBump); + assert.equal(bank.insuranceVaultAuthorityBump, insAuthBump); + + const [_feeVaultAuth, feeAuthBump] = deriveFeeVaultAuthority(id, bankKey); + const [feeVault, feeVaultBump] = deriveFeeVault(id, bankKey); + assertKeysEqual(bank.feeVault, feeVault); + assert.equal(bank.feeVaultBump, feeVaultBump); + assert.equal(bank.feeVaultAuthorityBump, feeAuthBump); + + assertKeyDefault(bank.emissionsMint); + + // Constants/Defaults... + assertI80F48Equal(bank.assetShareValue, 1); + assertI80F48Equal(bank.liabilityShareValue, 1); + assertI80F48Equal(bank.collectedInsuranceFeesOutstanding, 0); + assertI80F48Equal(bank.collectedGroupFeesOutstanding, 0); + assertI80F48Equal(bank.totalLiabilityShares, 0); + assertI80F48Equal(bank.totalAssetShares, 0); + assertBNEqual(bank.flags, 0); + assertBNEqual(bank.emissionsRate, 0); + assertI80F48Equal(bank.emissionsRemaining, 0); + + // Settings and non-default values... + let lastUpdate = bank.lastUpdate.toNumber(); + assert.approximately(now, lastUpdate, 2); + assertI80F48Equal(config.assetWeightInit, 1); + assertI80F48Equal(config.assetWeightMaint, 1); + assertI80F48Equal(config.liabilityWeightInit, 1); + assertBNEqual(config.depositLimit, 1_000_000_000); + + const tolerance = 0.000001; + assertI80F48Approx(interest.optimalUtilizationRate, 0.5, tolerance); + assertI80F48Approx(interest.plateauInterestRate, 0.6, tolerance); + assertI80F48Approx(interest.maxInterestRate, 3, tolerance); + assertI80F48Equal(interest.insuranceFeeFixedApr, 0); + assertI80F48Equal(interest.insuranceIrFee, 0); + assertI80F48Equal(interest.protocolFixedFeeApr, 0); + assertI80F48Equal(interest.protocolIrFee, 0); + + assert.deepEqual(config.operationalState, { operational: {} }); + assert.deepEqual(config.oracleSetup, { pythLegacy: {} }); + assertBNEqual(config.borrowLimit, 1_000_000_000); + assert.deepEqual(config.riskTier, { collateral: {} }); + assertBNEqual(config.totalAssetValueInitLimit, 100_000_000_000); + assert.equal(config.oracleMaxAge, 100); + }); + + it("(admin) Add bank (token A) - happy path", async () => { + let config = defaultBankConfig(oracles.tokenAOracle.publicKey); + let bankKey = bankKeypairA.publicKey; + + await groupAdmin.userMarginProgram!.provider.sendAndConfirm!( + new Transaction().add( + await addBank(program, { + marginfiGroup: marginfiGroup.publicKey, + admin: groupAdmin.wallet.publicKey, + feePayer: groupAdmin.wallet.publicKey, + bankMint: ecosystem.tokenAMint.publicKey, + bank: bankKey, + config: config, + }) + ), + [bankKeypairA] + ); + + if (verbose) { + console.log("*init token A bank " + bankKey); + } + }); + + it("Decodes a mainnet bank configured before manual padding", async () => { + // mainnet program ID + const id = new PublicKey("MFv2hWf31Z9kbCa1snEPYctwafyhdvnV7FZnsebVacA"); + const tolerance = 0.000001; + const group = new PublicKey("4qp6Fx6tnZkY5Wropq9wUYgtFxXKwE6viZxFHg3rdAG8"); + + let bonkBankKey = new PublicKey( + "DeyH7QxWvnbbaVB4zFrf4hoq7Q8z1ZT14co42BGwGtfM" + ); + let bonkBankData = ( + await program.provider.connection.getAccountInfo(bonkBankKey) + ).data.subarray(8); + printBufferGroups(bonkBankData, 16, 896); + + let cloudBankKey = new PublicKey( + "4kNXetv8hSv9PzvzPZzEs1CTH6ARRRi2b8h6jk1ad1nP" + ); + let cloudBankData = ( + await program.provider.connection.getAccountInfo(cloudBankKey) + ).data.subarray(8); + printBufferGroups(cloudBankData, 16, 896); + + const bbk = bonkBankKey; + const bb = await program.account.bank.fetch(bonkBankKey); + const bonkConfig = bb.config; + const bonkInterest = bonkConfig.interestRateConfig; + + assertKeysEqual( + bb.mint, + new PublicKey("DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263") + ); + assert.equal(bb.mintDecimals, 5); + assertKeysEqual(bb.group, group); + + const [_liqAu_bb, liqAuBmp_bb] = deriveLiquidityVaultAuthority(id, bbk); + const [liquidityVault_bb, liqVaultBump_bb] = deriveLiquidityVault(id, bbk); + assertKeysEqual(bb.liquidityVault, liquidityVault_bb); + assert.equal(bb.liquidityVaultBump, liqVaultBump_bb); + assert.equal(bb.liquidityVaultAuthorityBump, liqAuBmp_bb); + + const [_insAu_bb, insAuBmp_bb] = deriveInsuranceVaultAuthority(id, bbk); + const [insVault_bb, insVaultBump_bb] = deriveInsuranceVault(id, bbk); + assertKeysEqual(bb.insuranceVault, insVault_bb); + assert.equal(bb.insuranceVaultBump, insVaultBump_bb); + assert.equal(bb.insuranceVaultAuthorityBump, insAuBmp_bb); + + const [_feeVaultAuth_bb, feeAuthBump_bb] = deriveFeeVaultAuthority(id, bbk); + const [feeVault_bb, feeVaultBump_bb] = deriveFeeVault(id, bbk); + assertKeysEqual(bb.feeVault, feeVault_bb); + assert.equal(bb.feeVaultBump, feeVaultBump_bb); + assert.equal(bb.feeVaultAuthorityBump, feeAuthBump_bb); + + assertKeyDefault(bb.emissionsMint); + + // Constants/Defaults... + // assertI80F48Equal(bank.assetShareValue, 1); + // assertI80F48Equal(bank.liabilityShareValue, 1); + // assertI80F48Equal(bank.collectedInsuranceFeesOutstanding, 0); + // assertI80F48Equal(bank.collectedGroupFeesOutstanding, 0); + // assertI80F48Equal(bank.totalLiabilityShares, 0); + // assertI80F48Equal(bank.totalAssetShares, 0); + assertBNEqual(bb.flags, 0); + assertBNEqual(bb.emissionsRate, 0); + assertI80F48Equal(bb.emissionsRemaining, 0); + + // Settings and non-default values... + // let lastUpdate = bank.lastUpdate.toNumber(); + // assert.approximately(now, lastUpdate, 2); + // assertI80F48Equal(config.assetWeightInit, 1); + // assertI80F48Equal(config.assetWeightMaint, 1); + // assertI80F48Equal(config.liabilityWeightInit, 1); + + // 1 trillion BONK with 5 decimals (100_000_000_000_000_000) + assertBNEqual(bonkConfig.depositLimit, new BN("100000000000000000")); + + // assertI80F48Approx(interest.optimalUtilizationRate, 0.5, tolerance); + // assertI80F48Approx(interest.plateauInterestRate, 0.6, tolerance); + // assertI80F48Approx(interest.maxInterestRate, 3, tolerance); + // assertI80F48Equal(interest.insuranceFeeFixedApr, 0); + // assertI80F48Equal(interest.insuranceIrFee, 0); + // assertI80F48Equal(interest.protocolFixedFeeApr, 0); + // assertI80F48Equal(interest.protocolIrFee, 0); + + assert.deepEqual(bonkConfig.operationalState, { operational: {} }); + assert.deepEqual(bonkConfig.oracleSetup, { pythPushOracle: {} }); + // roughly 26.41 billion BONK with 5 decimals. + assertBNEqual(bonkConfig.borrowLimit, 2_640_570_785_700_000); + assert.deepEqual(bonkConfig.riskTier, { collateral: {} }); + assertBNEqual(bonkConfig.totalAssetValueInitLimit, 38_866_899); + assert.equal(bonkConfig.oracleMaxAge, 120); + + const cbk = cloudBankKey; + const cb = await program.account.bank.fetch(cloudBankKey); + const cloudConfig = cb.config; + const cloudInterest = cloudConfig.interestRateConfig; + + assertKeysEqual( + cb.mint, + new PublicKey("CLoUDKc4Ane7HeQcPpE3YHnznRxhMimJ4MyaUqyHFzAu") + ); + assert.equal(cb.mintDecimals, 9); + assertKeysEqual(cb.group, group); + + const [_liqAu_cb, liqAuBmp_cb] = deriveLiquidityVaultAuthority(id, cbk); + const [liquidityVault_cb, liqVaultBump_cb] = deriveLiquidityVault(id, cbk); + assertKeysEqual(cb.liquidityVault, liquidityVault_cb); + assert.equal(cb.liquidityVaultBump, liqVaultBump_cb); + assert.equal(cb.liquidityVaultAuthorityBump, liqAuBmp_cb); + + const [_insAu_cb, insAuBmp_cb] = deriveInsuranceVaultAuthority(id, cbk); + const [insVault_cb, insVaultBump_cb] = deriveInsuranceVault(id, cbk); + assertKeysEqual(cb.insuranceVault, insVault_cb); + assert.equal(cb.insuranceVaultBump, insVaultBump_cb); + assert.equal(cb.insuranceVaultAuthorityBump, insAuBmp_cb); + + const [_feeVaultAuth_cb, feeAuthBump_cb] = deriveFeeVaultAuthority(id, cbk); + const [feeVault_cb, feeVaultBump_cb] = deriveFeeVault(id, cbk); + assertKeysEqual(cb.feeVault, feeVault_cb); + assert.equal(cb.feeVaultBump, feeVaultBump_cb); + assert.equal(cb.feeVaultAuthorityBump, feeAuthBump_cb); + + assertKeyDefault(cb.emissionsMint); + + assertBNEqual(cb.flags, 0); + assertBNEqual(cb.emissionsRate, 0); + assertI80F48Equal(cb.emissionsRemaining, 0); + + // 1 million CLOUD with 9 decimals (1_000_000_000_000_000) + assertBNEqual(cloudConfig.depositLimit, 1_000_000_000_000_000); + + assert.deepEqual(cloudConfig.operationalState, { operational: {} }); + assert.deepEqual(cloudConfig.oracleSetup, { switchboardV2: {} }); + // 50,000 CLOUD with 9 decimals (50_000_000_000_000) + assertBNEqual(cloudConfig.borrowLimit, 50_000_000_000_000); + assert.deepEqual(cloudConfig.riskTier, { isolated: {} }); + assertBNEqual(cloudConfig.totalAssetValueInitLimit, 0); + assert.equal(cloudConfig.oracleMaxAge, 60); + }); +}); diff --git a/tests/fixtures/bonk_bank.json b/tests/fixtures/bonk_bank.json new file mode 100644 index 000000000..547360f40 --- /dev/null +++ b/tests/fixtures/bonk_bank.json @@ -0,0 +1,14 @@ +{ + "pubkey": "DeyH7QxWvnbbaVB4zFrf4hoq7Q8z1ZT14co42BGwGtfM", + "account": { + "lamports": 13864320, + "data": [ + "jjGm8jJCYby8B8VuYK09PxdzgurGVI+6H9Ms/ZDKArPnz6GF/c5zmAU5FC9oL9g4hJbsvVEG8Vx5TCR3Qzgo+mZC2+v3IANKYQAAAAAAAAAH7XQ4CQABAAAAAAAAAAAAUNKaShMDAQAAAAAAAAAAAFzlbG/YKG1ihwzjTpXeSCz7FIr2l01l8218yTibFnS3/P0CcaJzPtE3LyjGzOuP/wjpdl0sgXZ7i0qrUu0t2zHADv//AAAAAPZI716C4B6wAwAAAAAAAABnhNZ6oVeYGzSiP937qE9gqWYX4fOltZuMphcq7Z7Fuv7/AAAAAAAAZxEIzik2jTlJ79MGAAAAAN1wRLvkQ3UtFdFMlgMAAAD8eogH20TycL6/RqE0AQAAH+zEZgAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAZmamAAAAAAAAAAAAAAAAAMzMTAEAAAAAAAAAAAAAAAA0MzMBAAAAAAAAAAAAAACKXXhFYwHNzMzMzMwAAAAAAAAAAAAAzczMzMxMAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMP1KFyPAgAAAAAAAAAAAADD9ShcjyIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABA3KwISF8o/5okioZqvmQEJy52E6a0AS00gJa1vUpMUQZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgmK/LlWEJAAAAAAAAAAAA0w9RAgAAAAB4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==", + "base64" + ], + "owner": "MFv2hWf31Z9kbCa1snEPYctwafyhdvnV7FZnsebVacA", + "executable": false, + "rentEpoch": 18446744073709551615, + "space": 1864 + } +} \ No newline at end of file diff --git a/tests/fixtures/cloud_bank.json b/tests/fixtures/cloud_bank.json new file mode 100644 index 000000000..f9829ef3e --- /dev/null +++ b/tests/fixtures/cloud_bank.json @@ -0,0 +1,14 @@ +{ + "pubkey": "4kNXetv8hSv9PzvzPZzEs1CTH6ARRRi2b8h6jk1ad1nP", + "account": { + "lamports": 13864320, + "data": [ + "jjGm8jJCYbyogyJqGFxrMisI4fefQo4wDT4zW6GgTHhlNJGaBvfZ8gk5FC9oL9g4hJbsvVEG8Vx5TCR3Qzgo+mZC2+v3IANKYQAAAAAAAAAs3CCdPQABAAAAAAAAAAAA/tkGsN0AAQAAAAAAAAAAAFqTdNGj30RAPJUB2FxDdTaiQK81nAtNoC036eETPCSh//p7JBMzI1J2TnJXaz6SDMKe3DxZ7QTNyT0VRLNMhmF6XP7/AAAAAAsOCie/5VEAAAAAAAAAAABPATDgNn7MBOPOgG0ZBuCJYeC7tAxd7ySm24iypihR6f77AAAAAAAAxF9HPV+oYT5JYgoAAAAAACc+mwXs5Y0c3EtSLQAAAAClWKbWb3E0+LsL8mgCAAAAEN3EZgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAIAAAAAAAAAAAAAAAAAAIABAAAAAAAAAAAAAIDGpH6NAwDNzMzMzMwAAAAAAAAAAAAAmpmZmZkZAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMP1KFyPAgAAAAAAAAAAAADNzMzMzAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAncWuZMDstDPvGDjb7auLA4prc6DC5CLlvLSNUQf0XjqAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAID2IeS0AAAEAAAAAAAAAAAAAAAAAAAA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==", + "base64" + ], + "owner": "MFv2hWf31Z9kbCa1snEPYctwafyhdvnV7FZnsebVacA", + "executable": false, + "rentEpoch": 18446744073709551615, + "space": 1864 + } +} \ No newline at end of file diff --git a/tests/marginfi.ts b/tests/marginfi.ts deleted file mode 100644 index 3f592e8e0..000000000 --- a/tests/marginfi.ts +++ /dev/null @@ -1,16 +0,0 @@ -import * as anchor from "@project-serum/anchor"; -import { Program } from "@project-serum/anchor"; -import { Marginfi } from "../clients/typescript/packages/marginfi-client-v2/src/idl/marginfi"; - -describe("marginfi", () => { - // Configure the client to use the local cluster. - anchor.setProvider(anchor.AnchorProvider.env()); - - const program = anchor.workspace.Marginfi as Program; - - it("Is initialized!", async () => { - // Add your test here. - const tx = await program.methods.initialize().rpc(); - console.log("Your transaction signature", tx); - }); -}); diff --git a/tests/rootHooks.ts b/tests/rootHooks.ts new file mode 100644 index 000000000..bf72966a7 --- /dev/null +++ b/tests/rootHooks.ts @@ -0,0 +1,117 @@ +import { workspace, Program, AnchorProvider, Wallet } from "@coral-xyz/anchor"; +import { + createSimpleMint, + echoEcosystemInfo, + Ecosystem, + getGenericEcosystem, + mockUser, + Oracles, + setupTestUser, + SetupTestUserOptions, +} from "./utils/mocks"; +import { Marginfi } from "../target/types/marginfi"; +import { Keypair, Transaction } from "@solana/web3.js"; +import { setupPythOracles } from "./utils/pyth_mocks"; + +export const ecosystem: Ecosystem = getGenericEcosystem(); +export let oracles: Oracles = undefined; +export const verbose = true; +/** The program owner is also the provider wallet */ +export let globalProgramAdmin: mockUser = undefined; +export let groupAdmin: mockUser = undefined; +export const users: mockUser[] = []; +export const numUsers = 2; + +/** Group used for all happy-path tests */ +export const marginfiGroup = Keypair.generate(); +/** Bank for USDC */ +export const bankKeypairUsdc = Keypair.generate(); +/** Bank for token A */ +export const bankKeypairA = Keypair.generate(); + +export const mochaHooks = { + beforeAll: async () => { + const program = workspace.Marginfi as Program; + const provider = AnchorProvider.local(); + const wallet = provider.wallet as Wallet; + + if (verbose) { + console.log("Global Ecosystem Information "); + echoEcosystemInfo(ecosystem, { + skipA: false, + skipB: false, + skipUsdc: false, + skipWsol: true, + }); + console.log(""); + } + + const { ixes: usdcIxes, mint: usdcMint } = await createSimpleMint( + provider.publicKey, + provider.connection, + ecosystem.usdcDecimals, + ecosystem.usdcMint + ); + + const { ixes: aIxes, mint: aMint } = await createSimpleMint( + provider.publicKey, + provider.connection, + ecosystem.tokenADecimals, + ecosystem.tokenAMint + ); + const { ixes: bIxes, mint: bMint } = await createSimpleMint( + provider.publicKey, + provider.connection, + ecosystem.tokenBDecimals, + ecosystem.tokenBMint + ); + const tx = new Transaction(); + tx.add(...usdcIxes); + tx.add(...aIxes); + tx.add(...bIxes); + + await provider.sendAndConfirm(tx, [usdcMint, aMint, bMint]); + + const setupUserOptions: SetupTestUserOptions = { + marginProgram: program, + forceWallet: undefined, + // If mints are created, typically create the ATA too, otherwise pass undefined... + wsolMint: undefined, + tokenAMint: ecosystem.tokenAMint.publicKey, + tokenBMint: ecosystem.tokenBMint.publicKey, + usdcMint: ecosystem.usdcMint.publicKey, + }; + + groupAdmin = await setupTestUser(provider, wallet.payer, setupUserOptions); + + for (let i = 0; i < numUsers; i++) { + const user = await setupTestUser( + provider, + wallet.payer, + setupUserOptions + ); + users.push(user); + } + + // Global admin uses the payer wallet... + setupUserOptions.forceWallet = wallet.payer; + globalProgramAdmin = await setupTestUser( + provider, + wallet.payer, + setupUserOptions + ); + + oracles = await setupPythOracles( + wallet, + 150, + ecosystem.wsolDecimals, + 1, + ecosystem.usdcDecimals, + 10, + ecosystem.tokenADecimals, + 20, + ecosystem.tokenBDecimals, + verbose + ); + }, +}; diff --git a/tests/utils/genericTests.ts b/tests/utils/genericTests.ts new file mode 100644 index 000000000..3923219b1 --- /dev/null +++ b/tests/utils/genericTests.ts @@ -0,0 +1,175 @@ +import type { AnchorProvider } from "@coral-xyz/anchor"; +import { WrappedI80F48, wrappedI80F48toBigNumber } from "@mrgnlabs/mrgn-common"; +import type { RawAccount } from "@solana/spl-token"; +import { AccountLayout } from "@solana/spl-token"; +import { PublicKey } from "@solana/web3.js"; +import BigNumber from "bignumber.js"; +import BN from "bn.js"; +import { assert } from "chai"; + +/** + * Shorthand for `assert.equal(a.toString(), b.toString())` + * @param a + * @param b + */ +export const assertKeysEqual = (a: PublicKey, b: PublicKey) => { + assert.equal(a.toString(), b.toString()); +}; + +/** + * Shorthand for `assert.equal(a.toString(), PublicKey.default.toString())` + * @param a + */ +export const assertKeyDefault = (a: PublicKey) => { + assert.equal(a.toString(), PublicKey.default.toString()); +}; + +/** + * Shorthand for `assert.equal(a.toString(), b.toString())` + * @param a - a BN + * @param b - a BN or number + */ +export const assertBNEqual = (a: BN, b: BN | number) => { + if (typeof b === "number") { + b = new BN(b); + } + assert.equal(a.toString(), b.toString()); +}; + +/** + * Shorthand to convert I80F48 to a string and compare against a BN, number, or other WrappedI80F48 + * + * Generally, use `assertI80F48Approx` instead if the expected value is not a whole number or zero. + * @param a + * @param b + */ +export const assertI80F48Equal = ( + a: WrappedI80F48, + b: WrappedI80F48 | BN | number +) => { + const bigA = wrappedI80F48toBigNumber(a); + let bigB: BigNumber; + + if (typeof b === "number") { + bigB = new BigNumber(b); + } else if (b instanceof BN) { + bigB = new BigNumber(b.toString()); + } else if (isWrappedI80F48(b)) { + bigB = wrappedI80F48toBigNumber(b); + } else { + throw new Error("Unsupported type for comparison"); + } + + assert.equal(bigA.toString(), bigB.toString()); +}; + +/** + * Shorthand to convert I80F48 to a string and compare against a BN, number, or other WrappedI80F48 within a given tolerance + * @param a + * @param b + * @param tolerance - the allowed difference between the two values + */ +export const assertI80F48Approx = ( + a: WrappedI80F48, + b: WrappedI80F48 | BN | number, + tolerance: number +) => { + const bigA = wrappedI80F48toBigNumber(a); + let bigB: BigNumber; + + if (typeof b === "number") { + bigB = new BigNumber(b); + } else if (b instanceof BN) { + bigB = new BigNumber(b.toString()); + } else if (isWrappedI80F48(b)) { + bigB = wrappedI80F48toBigNumber(b); + } else { + throw new Error("Unsupported type for comparison"); + } + + const diff = bigA.minus(bigB).abs(); + const allowedDifference = new BigNumber(tolerance); + + if (diff.isGreaterThan(allowedDifference)) { + throw new Error( + `Values are not approximately equal. Difference: ${diff.toString()}, Allowed Tolerance: ${tolerance}` + ); + } +}; + +/** + * Type guard to check if a value is WrappedI80F48 + * @param value + * @returns + */ +function isWrappedI80F48(value: any): value is WrappedI80F48 { + return value && typeof value === "object" && Array.isArray(value.value); +} + +/** + * Shorthand for `assert.approximately(a, b, tolerance)` for two BNs. Safe from Integer overflow + * @param a + * @param b + * @param tolerance + */ +export const assertBNApproximately = ( + a: BN, + b: BN | number, + tolerance: BN | number +) => { + const aB = BigInt(a.toString()); + const bB = BigInt(b.toString()); + const toleranceB = BigInt(tolerance.toString()); + assert.ok(aB >= bB - toleranceB); + assert.ok(aB <= bB + toleranceB); +}; + +/** + * Returns the balance of a token account, in whatever currency the account is in. + * @param provider + * @param account + * @returns + */ +export const getTokenBalance = async ( + provider: AnchorProvider, + account: PublicKey +) => { + const accountInfo = await provider.connection.getAccountInfo(account); + if (!accountInfo) { + console.error("Tried to balance of acc that doesn't exist"); + return 0; + } + const data: RawAccount = AccountLayout.decode(accountInfo.data); + if (data === undefined || data.amount === undefined) { + return 0; + } + const amount: BigInt = data.amount; + return Number(amount); +}; + +/** + * Waits until the given time + * @param time - in seconds (e.g. Date.now()/1000) + * @param silenceWarning - (optional) set to true to silence the warning if the time is in the past + */ +export const waitUntil = async ( + time: number, + silenceWarning: boolean = false +) => { + const now = Date.now() / 1000; + if (time > now + 500) { + console.error("Tried to wait a very long time, aborted"); + return; + } + if (now > time) { + if (!silenceWarning) { + console.error( + "Tried to wait for a time that's in the past. You probably need to adjust test timings." + ); + console.error("now: " + now + " and tried waiting until: " + time); + } + return new Promise((r) => setTimeout(r, 1)); //waits 1 ms + } + const toWait = Math.ceil(time - now) * 1000; + await new Promise((r) => setTimeout(r, toWait)); +}; diff --git a/tests/utils/instructions.ts b/tests/utils/instructions.ts new file mode 100644 index 000000000..10c1f9241 --- /dev/null +++ b/tests/utils/instructions.ts @@ -0,0 +1,123 @@ +import { Program } from "@coral-xyz/anchor"; +import { AccountMeta, PublicKey, SYSVAR_RENT_PUBKEY } from "@solana/web3.js"; +import { Marginfi } from "../../target/types/marginfi"; +import { + deriveFeeVault, + deriveFeeVaultAuthority, + deriveInsuranceVault, + deriveInsuranceVaultAuthority, + deriveLiquidityVault, + deriveLiquidityVaultAuthority, +} from "./pdas"; +import { BankConfig } from "./types"; +import { TOKEN_PROGRAM_ID } from "@solana/spl-token"; + +export const MAX_ORACLE_KEYS = 5; + +/** + * * admin/feePayer - must sign + * * bank - use a fresh keypair, must sign + */ +export type AddBankArgs = { + marginfiGroup: PublicKey; + admin: PublicKey; + feePayer: PublicKey; + bankMint: PublicKey; + bank: PublicKey; + config: BankConfig; +}; + +export const addBank = (program: Program, args: AddBankArgs) => { + // const id = program.programId; + // const bank = args.bank; + + // Note that oracle is passed as a key in config and as an acc in remaining accs... + const oracleMeta: AccountMeta = { + pubkey: args.config.oracleKey, + isSigner: false, + isWritable: false, + }; + + const ix = program.methods + .lendingPoolAddBank({ + assetWeightInit: args.config.assetWeightInit, + assetWeightMaint: args.config.assetWeightMaint, + liabilityWeightInit: args.config.liabilityWeightInit, + liabilityWeightMaint: args.config.liabilityWeightMain, + depositLimit: args.config.depositLimit, + interestRateConfig: args.config.interestRateConfig, + operationalState: args.config.operationalState, + oracleSetup: args.config.oracleSetup, + oracleKey: args.config.oracleKey, + borrowLimit: args.config.borrowLimit, + riskTier: args.config.riskTier, + totalAssetValueInitLimit: args.config.totalAssetValueInitLimit, + oracleMaxAge: args.config.oracleMaxAge, + }) + .accounts({ + marginfiGroup: args.marginfiGroup, + admin: args.admin, + feePayer: args.feePayer, + bankMint: args.bankMint, + bank: args.bank, + // liquidityVaultAuthority = deriveLiquidityVaultAuthority(id, bank); + // liquidityVault = deriveLiquidityVault(id, bank); + // insuranceVaultAuthority = deriveInsuranceVaultAuthority(id, bank); + // insuranceVault = deriveInsuranceVault(id, bank); + // feeVaultAuthority = deriveFeeVaultAuthority(id, bank); + // feeVault = deriveFeeVault(id, bank); + // rent = SYSVAR_RENT_PUBKEY + tokenProgram: TOKEN_PROGRAM_ID, + // systemProgram: SystemProgram.programId, + }) + .remainingAccounts([oracleMeta]) + .instruction(); + + return ix; +}; + +/** + * newAdmin - (Optional) pass null to keep current admin + * admin - must sign, must be current admin of marginfiGroup + */ +export type GroupConfigureArgs = { + newAdmin: PublicKey | null; + marginfiGroup: PublicKey; + admin: PublicKey; +}; + +export const groupConfigure = ( + program: Program, + args: GroupConfigureArgs +) => { + const ix = program.methods + .marginfiGroupConfigure({ admin: args.newAdmin }) + .accounts({ + marginfiGroup: args.marginfiGroup, + admin: args.admin, + }) + .instruction(); + + return ix; +}; + +export type GroupInitializeArgs = { + marginfiGroup: PublicKey; + admin: PublicKey; +}; + +export const groupInitialize = ( + program: Program, + args: GroupInitializeArgs +) => { + const ix = program.methods + .marginfiGroupInitialize() + .accounts({ + marginfiGroup: args.marginfiGroup, + admin: args.admin, + // systemProgram: SystemProgram.programId, + }) + .instruction(); + + return ix; +}; diff --git a/tests/utils/mocks.ts b/tests/utils/mocks.ts new file mode 100644 index 000000000..69a139814 --- /dev/null +++ b/tests/utils/mocks.ts @@ -0,0 +1,347 @@ +import { AnchorProvider, BN, Program, Wallet } from "@coral-xyz/anchor"; +import { + createAssociatedTokenAccountInstruction, + createInitializeMintInstruction, + getAssociatedTokenAddressSync, + MintLayout, + TOKEN_PROGRAM_ID, +} from "@solana/spl-token"; +import type { Connection, TransactionInstruction } from "@solana/web3.js"; +import { + Keypair, + LAMPORTS_PER_SOL, + PublicKey, + SystemProgram, + Transaction, +} from "@solana/web3.js"; +import { Marginfi } from "../../target/types/marginfi"; +import { Mocks } from "../../target/types/mocks"; + +export type Ecosystem = { + /** A generic wsol mint with 9 decimals (same as native) */ + wsolMint: Keypair; + /** A generic spl token mint */ + tokenAMint: Keypair; + /** A generic spl token mint */ + tokenBMint: Keypair; + /** A generic spl token mint like USDC (6 decimals) */ + usdcMint: Keypair; + /** 9 */ + wsolDecimals: number; + /** Decimals for token A (default 8) */ + tokenADecimals: number; + /** Decimals for token B (default 6)*/ + tokenBDecimals: number; + /** 6 */ + usdcDecimals: number; +}; + +/** + * Random keypairs for all mints. + * + * 6 Decimals for usdc. 9 decimals for sol. 8 decimals to token A, 6 for token B + * @returns + */ +export const getGenericEcosystem = () => { + const ecosystem: Ecosystem = { + wsolMint: Keypair.generate(), + tokenAMint: Keypair.generate(), + tokenBMint: Keypair.generate(), + usdcMint: Keypair.generate(), + wsolDecimals: 9, + tokenADecimals: 8, + tokenBDecimals: 6, + usdcDecimals: 6, + }; + return ecosystem; +}; + +/** + * Print ecosystem info to console + * @param ecosystem + */ +export const echoEcosystemInfo = ( + ecosystem: Ecosystem, + { skipWsol = false, skipUsdc = false, skipA = false, skipB = false } +) => { + if (!skipWsol) { + console.log("wsol mint:........... " + ecosystem.wsolMint.publicKey); + console.log(" wsol decimals...... " + ecosystem.wsolDecimals); + } + if (!skipUsdc) { + console.log("usdc mint:........... " + ecosystem.usdcMint.publicKey); + console.log(" usdc decimals:..... " + ecosystem.usdcDecimals); + } + if (!skipA) { + console.log("token a mint:........ " + ecosystem.tokenAMint.publicKey); + console.log(" token a decimals:.. " + ecosystem.tokenADecimals); + } + if (!skipB) { + console.log("token b mint:........ " + ecosystem.tokenBMint.publicKey); + console.log(" token b decimals:.. " + ecosystem.tokenBDecimals); + } +}; + +/** + * A typical user, with a wallet, ATAs for mock tokens, and a program to sign/send txes with. + */ +export type mockUser = { + wallet: Keypair; + /** Users's ATA for wsol*/ + wsolAccount: PublicKey; + /** Users's ATA for token A */ + tokenAAccount: PublicKey; + /** Users's ATA for token B */ + tokenBAccount: PublicKey; + /** Users's ATA for USDC */ + usdcAccount: PublicKey; + /** A program that uses the user's wallet */ + userMarginProgram: Program | undefined; +}; + +/** + * Options to skip various parts of mock user setup + */ +export interface SetupTestUserOptions { + marginProgram: Program; + /** Force the mock user to use this keypair */ + forceWallet: Keypair; + wsolMint: PublicKey; + tokenAMint: PublicKey; + tokenBMint: PublicKey; + usdcMint: PublicKey; +} + +/** + * Creates and funds a user by transfering some SOL from a given wallet. + * + * Opens ATA for the user on all ecosystem mints + * + * Initializes a mock program to sign transactions as the user + * @param provider + * @param wallet - provider wallet, pays init and tx fees + * @param options - skip parts of setup or force a keypair as the wallet + * @returns + */ +export const setupTestUser = async ( + provider: AnchorProvider, + wallet: Keypair, + options?: SetupTestUserOptions +) => { + // Creates a user wallet with some SOL in it to pay tx fees + const userWalletKeypair = options.forceWallet || Keypair.generate(); + const userWallet = userWalletKeypair.publicKey; + const tx: Transaction = new Transaction(); + tx.add( + SystemProgram.transfer({ + fromPubkey: wallet.publicKey, + toPubkey: userWallet, + lamports: 1000 * LAMPORTS_PER_SOL, + }) + ); + + let wsolAccount: PublicKey = PublicKey.default; + if (options.wsolMint) { + wsolAccount = getAssociatedTokenAddressSync(options.wsolMint, userWallet); + tx.add( + createAssociatedTokenAccountInstruction( + wallet.publicKey, + wsolAccount, + userWallet, + options.wsolMint + ) + ); + } + + let usdcAccount: PublicKey = PublicKey.default; + if (options.usdcMint) { + usdcAccount = getAssociatedTokenAddressSync(options.usdcMint, userWallet); + tx.add( + createAssociatedTokenAccountInstruction( + wallet.publicKey, + usdcAccount, + userWallet, + options.usdcMint + ) + ); + } + + let tokenAAccount: PublicKey = PublicKey.default; + if (options.tokenAMint) { + tokenAAccount = getAssociatedTokenAddressSync( + options.tokenAMint, + userWallet + ); + tx.add( + createAssociatedTokenAccountInstruction( + wallet.publicKey, + tokenAAccount, + userWallet, + options.tokenAMint + ) + ); + } + + let tokenBAccount: PublicKey = PublicKey.default; + if (options.tokenBMint) { + tokenBAccount = getAssociatedTokenAddressSync( + options.tokenBMint, + userWallet + ); + tx.add( + createAssociatedTokenAccountInstruction( + wallet.publicKey, + tokenBAccount, + userWallet, + options.tokenBMint + ) + ); + } + + await provider.sendAndConfirm(tx, [wallet]); + + const user: mockUser = { + wallet: userWalletKeypair, + wsolAccount: wsolAccount, + tokenAAccount: tokenAAccount, + tokenBAccount: tokenBAccount, + usdcAccount: usdcAccount, + + userMarginProgram: options.marginProgram + ? getUserMarginfiProgram(options.marginProgram, userWalletKeypair) + : undefined, + }; + return user; +}; + +/** + * Generates a mock program that can sign transactions as the user's wallet + * @param program + * @param userWallet + * @returns + */ +export const getUserMarginfiProgram = ( + program: Program, + userWallet: Keypair | Wallet +) => { + const wallet = + userWallet instanceof Keypair ? new Wallet(userWallet) : userWallet; + const provider = new AnchorProvider(program.provider.connection, wallet, {}); + const userProgram = new Program(program.idl, provider); + return userProgram; +}; + +/** + * Ixes to create a mint, the payer gains the Mint Tokens/Freeze authority + * @param payer - pays account init fees, must sign, gains mint/freeze authority + * @param provider + * @param decimals + * @param mintKeypair - (optional) generates random keypair if not provided, must sign + * @param lamps - (optional) lamports to pay for created acc, fetches minimum for Mint exemption if + * not provided + * @returns ixes, and keypair of new mint + */ +export const createSimpleMint = async ( + payer: PublicKey, + connection: Connection, + decimals: number, + mintKeypair?: Keypair, + lamps?: number +) => { + const mint = mintKeypair ? mintKeypair : Keypair.generate(); + const ixes: TransactionInstruction[] = []; + const lamports = lamps + ? lamps + : await connection.getMinimumBalanceForRentExemption(MintLayout.span); + ixes.push( + SystemProgram.createAccount({ + fromPubkey: payer, + newAccountPubkey: mint.publicKey, + space: MintLayout.span, + lamports: lamports, + programId: TOKEN_PROGRAM_ID, + }) + ); + ixes.push( + createInitializeMintInstruction( + mint.publicKey, + decimals, + payer, + payer, + TOKEN_PROGRAM_ID + ) + ); + + return { ixes, mint }; +}; + +export type Oracles = { + wsolOracle: Keypair, + wsolPrice: number, + wsolDecimals: number, + usdcOracle: Keypair, + usdcPrice: number, + usdcDecimals: number, + tokenAOracle: Keypair, + tokenAPrice: number, + tokenADecimals: number, + tokenBOracle: Keypair, + tokenBPrice: number, + tokenBDecimals:number, +} + +/** + * Creates an account to store data arbitrary data. + * @param program - the mock program + * @param space - for account space and rent exemption + * @param wallet - pays tx fee + * @returns address of the newly created account + */ +export const createMockAccount = async ( + program: Program, + space: number, + wallet: Wallet +) => { + const newAccount = Keypair.generate(); + const createTx = new Transaction().add( + SystemProgram.createAccount({ + fromPubkey: wallet.publicKey, + newAccountPubkey: newAccount.publicKey, + programId: program.programId, + lamports: + await program.provider.connection.getMinimumBalanceForRentExemption( + space + ), + space, + }) + ); + + await program.provider.sendAndConfirm(createTx, [wallet.payer, newAccount]); + return newAccount; +}; + +/** + * Writes arbitrary bytes to a mock account + * @param program - the Mock program + * @param wallet - pays tx fee + * @param account - account to write into (create with `createMockAccount` first) + * @param offset - byte to start writing + * @param input - bytes to write + */ +export const storeMockAccount = async ( + program: Program, + wallet: Wallet, + account: Keypair, + offset: number, + input: Buffer +) => { + const tx = new Transaction().add( + await program.methods + .write(new BN(offset), input) + .accounts({ + target: account.publicKey, + }) + .instruction() + ); + await program.provider.sendAndConfirm(tx, [wallet.payer, account]); +}; \ No newline at end of file diff --git a/tests/utils/pdas.ts b/tests/utils/pdas.ts new file mode 100644 index 000000000..2594ccfad --- /dev/null +++ b/tests/utils/pdas.ts @@ -0,0 +1,52 @@ +import { PublicKey } from "@solana/web3.js"; + +export const deriveLiquidityVaultAuthority = ( + programId: PublicKey, + bank: PublicKey +) => { + return PublicKey.findProgramAddressSync( + [Buffer.from("liquidity_vault_auth", "utf-8"), bank.toBuffer()], + programId + ); +}; + +export const deriveLiquidityVault = (programId: PublicKey, bank: PublicKey) => { + return PublicKey.findProgramAddressSync( + [Buffer.from("liquidity_vault", "utf-8"), bank.toBuffer()], + programId + ); +}; + +export const deriveInsuranceVaultAuthority = ( + programId: PublicKey, + bank: PublicKey +) => { + return PublicKey.findProgramAddressSync( + [Buffer.from("insurance_vault_auth", "utf-8"), bank.toBuffer()], + programId + ); +}; + +export const deriveInsuranceVault = (programId: PublicKey, bank: PublicKey) => { + return PublicKey.findProgramAddressSync( + [Buffer.from("insurance_vault", "utf-8"), bank.toBuffer()], + programId + ); +}; + +export const deriveFeeVaultAuthority = ( + programId: PublicKey, + bank: PublicKey +) => { + return PublicKey.findProgramAddressSync( + [Buffer.from("fee_vault_auth", "utf-8"), bank.toBuffer()], + programId + ); +}; + +export const deriveFeeVault = (programId: PublicKey, bank: PublicKey) => { + return PublicKey.findProgramAddressSync( + [Buffer.from("fee_vault", "utf-8"), bank.toBuffer()], + programId + ); +}; diff --git a/tests/utils/pyth_mocks.ts b/tests/utils/pyth_mocks.ts new file mode 100644 index 000000000..929a9c755 --- /dev/null +++ b/tests/utils/pyth_mocks.ts @@ -0,0 +1,446 @@ +// Adapted from PsyLend +import { Program, Wallet, workspace } from "@coral-xyz/anchor"; +import { Keypair, PublicKey } from "@solana/web3.js"; +import { Oracles, createMockAccount, storeMockAccount } from "./mocks"; +import { Mocks } from "../../target/types/mocks"; +/** Copied from `@pythnetwork/client": "^2.19.0"`, used as a discriminator */ +const Magic = 2712847316; + +/** + * As long as it's large enough, any size is fine. + */ +const PYTH_ACCOUNT_SIZE = 3312; + +const mockProgram: Program = workspace.Mocks; + +export interface Price { + version?: number; + type?: number; + size?: number; + priceType?: string; + exponent?: number; + currentSlot?: bigint; + validSlot?: bigint; + twap?: Ema; + productAccountKey?: PublicKey; + nextPriceAccountKey?: PublicKey; + aggregatePriceUpdaterAccountKey?: PublicKey; + aggregatePriceInfo?: PriceInfo; + priceComponents?: PriceComponent[]; +} + +export interface PriceInfo { + price?: bigint; + conf?: bigint; + status?: number; + corpAct?: number; + pubSlot?: bigint; +} + +export interface PriceComponent { + publisher?: PublicKey; + agg?: PriceInfo; + latest?: PriceInfo; +} + +export interface Product { + version?: number; + atype?: number; + size?: number; + priceAccount?: PublicKey; + attributes?: Record; +} + +export interface Ema { + valueComponent?: bigint; + numerator?: bigint; + denominator?: bigint; +} + +/** + * Creates a Pyth price account + * @param wallet - pays the TX fee + * @returns + */ +export const createPriceAccount = async (wallet: Wallet) => { + return createMockAccount(mockProgram, PYTH_ACCOUNT_SIZE, wallet); +}; + +/** + * Creates a Pyth product account + * @param wallet - pays the TX fee + * @returns + */ +export const createProductAccount = async (wallet: Wallet) => { + return createMockAccount(mockProgram, PYTH_ACCOUNT_SIZE, wallet); +}; + +/** + * Update a Pyth price account with new data + * @param account The account to update + * @param data The new data to place in the account + * @param wallet - pays tx fee + */ +export const updatePriceAccount = async ( + account: Keypair, + data: Price, + wallet: Wallet +) => { + const buf = Buffer.alloc(512); + const d = getPythPriceDataWithDefaults(data); + d.aggregatePriceInfo = getPythPriceInfoWithDefaults(d.aggregatePriceInfo); + d.twap = getPythEmaWithDefaults(d.twap); + + writePriceBuffer(buf, 0, d); + await storeMockAccount(mockProgram, wallet, account, 0, buf); +}; + +/** + * Update a Pyth product account with new data + * @param account The account to update + * @param data The new data to place in the account + * @param wallet - pays tx fee + */ +export const updateProductAccount = async ( + account: Keypair, + data: Product, + wallet: Wallet +) => { + const buf = Buffer.alloc(512); + const d = getProductWithDefaults(data); + + writeProductBuffer(buf, 0, d); + await storeMockAccount(mockProgram, wallet, account, 0, buf); +}; + +export const getPythPriceDataWithDefaults = ({ + version = 2, + type = 3, // AccountType::Price + size = PYTH_ACCOUNT_SIZE, + priceType = "price", + exponent = 0, + currentSlot = BigInt(0), + validSlot = BigInt(0), + twap = {}, + productAccountKey = PublicKey.default, + nextPriceAccountKey = PublicKey.default, + aggregatePriceUpdaterAccountKey = PublicKey.default, + aggregatePriceInfo = {}, + priceComponents = [], +}: Price) => { + return { + version, + type, + size, + priceType, + exponent, + currentSlot, + validSlot, + twap, + productAccountKey, + nextPriceAccountKey, + aggregatePriceUpdaterAccountKey, + aggregatePriceInfo, + priceComponents, + }; +}; + +export const getPythPriceInfoWithDefaults = ({ + price = BigInt(0), + conf = BigInt(0), + status = 1, // PriceStatus::Trading + corpAct = 0, // CorpAction::NoCorpAct + pubSlot = BigInt(Number.MAX_SAFE_INTEGER), // Pubslot has to be newer than current slot. +}: PriceInfo) => { + return { + price, + conf, + status, + corpAct, + pubSlot, + }; +}; + +export const getPythEmaWithDefaults = ({ + valueComponent = BigInt(0), + denominator = BigInt(0), + numerator = BigInt(0), +}: Ema) => { + return { + valueComponent, + denominator, + numerator, + }; +}; + +export const writePublicKeyBuffer = ( + buf: Buffer, + offset: number, + key: PublicKey +) => { + buf.write(key.toBuffer().toString("binary"), offset, "binary"); +}; + +export const writePriceInfoBuffer = ( + buf: Buffer, + offset: number, + info: PriceInfo +) => { + buf.writeBigInt64LE(info.price, offset + 0); + buf.writeBigUInt64LE(info.conf, offset + 8); + buf.writeUInt32LE(info.status, offset + 16); + buf.writeUInt32LE(info.corpAct, offset + 20); + buf.writeBigUInt64LE(info.pubSlot, offset + 24); +}; + +export const writePriceComponentBuffer = ( + buf: Buffer, + offset: number, + component: PriceComponent +) => { + component.publisher.toBuffer().copy(buf, offset); + writePriceInfoBuffer(buf, offset + 32, component.agg); + writePriceInfoBuffer(buf, offset + 64, component.latest); +}; + +export const writePriceBuffer = (buf: Buffer, offset: number, data: Price) => { + buf.writeUInt32LE(Magic, offset + 0); //magic + buf.writeUInt32LE(data.version, offset + 4); //ver + buf.writeUInt32LE(data.type, offset + 8); //type + buf.writeUInt32LE(data.size, offset + 12); //size + buf.writeUInt32LE(1, offset + 16); //price type + buf.writeInt32LE(data.exponent, offset + 20); //exp + buf.writeUInt32LE(data.priceComponents.length, offset + 24); //price comps + buf.writeBigUInt64LE(data.currentSlot, offset + 32); //curr slot + buf.writeBigUInt64LE(data.validSlot, offset + 40); //valid slot + buf.writeBigInt64LE(data.twap.valueComponent, offset + 48); //ema + buf.writeBigInt64LE(data.twap.numerator, offset + 56); //ema + buf.writeBigInt64LE(data.twap.denominator, offset + 64); //ema + writePublicKeyBuffer(buf, offset + 112, data.productAccountKey); + writePublicKeyBuffer(buf, offset + 144, data.nextPriceAccountKey); + writePublicKeyBuffer(buf, offset + 176, data.aggregatePriceUpdaterAccountKey); + + writePriceInfoBuffer(buf, 208, data.aggregatePriceInfo); + + let pos = offset + 240; + for (const component of data.priceComponents) { + writePriceComponentBuffer(buf, pos, component); + pos += 96; + } +}; + +export const getProductWithDefaults = ({ + version = 2, + atype = 2, + size = 0, + priceAccount = PublicKey.default, + attributes = {}, +}: Product) => { + return { + version, + atype, + size, + priceAccount, + attributes, + }; +}; + +export const writeProductBuffer = ( + buf: Buffer, + offset: number, + product: Product +) => { + let accountSize = product.size; + + if (!accountSize) { + accountSize = 48; + + for (const key in product.attributes) { + accountSize += 1 + key.length; + accountSize += 1 + product.attributes[key].length; + } + } + + buf.writeUInt32LE(Magic, offset + 0); + buf.writeUInt32LE(product.version, offset + 4); + buf.writeUInt32LE(product.atype, offset + 8); + buf.writeUInt32LE(accountSize, offset + 12); + + writePublicKeyBuffer(buf, offset + 16, product.priceAccount); + + let pos = offset + 48; + + for (const key in product.attributes) { + buf.writeUInt8(key.length, pos); + buf.write(key, pos + 1); + + pos += 1 + key.length; + + const value = product.attributes[key]; + buf.writeUInt8(value.length, pos); + buf.write(value, pos + 1); + } +}; + +/** + * Set up mock usdc and wsol oracles + * @param wallet + * @param wsolPrice + * @param wsolDecimals + * @param usdcPrice + * @param usdcDecimals + * @param verbose + * @param skips - set to true to skip sending txes, which makes tests run faster if you don't need + * those oracles. + * @returns Price oracles for all currencies + */ +export const setupPythOracles = async ( + wallet: Wallet, + wsolPrice: number, + wsolDecimals: number, + usdcPrice: number, + usdcDecimals: number, + tokenAPrice: number, + tokenADecimals: number, + tokenBPrice: number, + tokenBDecimals: number, + verbose: boolean, + skips?: { + wsol: boolean; + usdc: boolean; + a: boolean; + b: boolean; + } +) => { + let wsolPythOracle = await createPriceAccount(wallet); + let price = BigInt(wsolPrice * 10 ** wsolDecimals); + if (skips && skips.wsol) { + // do nothing + } else { + await updatePriceAccount( + wsolPythOracle, + { + exponent: -wsolDecimals, + aggregatePriceInfo: { + price: price, + conf: price / BigInt(100), // 1% of the price + }, + twap: { + valueComponent: price, + }, + }, + wallet + ); + } + + let usdcPythOracle = await createPriceAccount(wallet); + price = BigInt(usdcPrice * 10 ** usdcDecimals); + if (skips && skips.usdc) { + // do nothing + } else { + await updatePriceAccount( + usdcPythOracle, + { + exponent: -usdcDecimals, + aggregatePriceInfo: { + price: price, + conf: price / BigInt(100), // 1% of the price + }, + twap: { + valueComponent: price, + }, + }, + wallet + ); + } + + let tokenAPythOracle = await createPriceAccount(wallet); + price = BigInt(tokenAPrice * 10 ** tokenADecimals); + if (skips && skips.a) { + // do nothing + } else { + await updatePriceAccount( + tokenAPythOracle, + { + exponent: -tokenADecimals, + aggregatePriceInfo: { + price: price, + conf: price / BigInt(100), // 1% of the price + }, + twap: { + valueComponent: price, + }, + }, + wallet + ); + } + + let tokenBPythOracle = await createPriceAccount(wallet); + price = BigInt(tokenBPrice * 10 ** tokenBDecimals); + if (skips && skips.b) { + // do nothing + } else { + await updatePriceAccount( + tokenBPythOracle, + { + exponent: -tokenBDecimals, + aggregatePriceInfo: { + price: price, + conf: price / BigInt(100), // 1% of the price + }, + twap: { + valueComponent: price, + }, + }, + wallet + ); + } + + if (verbose) { + console.log("Mock Pyth price oracles:"); + console.log("wsol price: \t" + wsolPythOracle.publicKey); + console.log("usdc price: \t" + usdcPythOracle.publicKey); + console.log("token a price: \t" + tokenAPythOracle.publicKey); + console.log("token b price: \t" + tokenBPythOracle.publicKey); + console.log( + "Price of 1 wsol.......$" + + wsolPrice + + "\t one token in native decimals: " + + (1 * 10 ** wsolDecimals).toLocaleString() + ); + console.log( + "Price of 1 usdc.......$" + + usdcPrice + + "\t one token in native decimals: " + + (1 * 10 ** usdcDecimals).toLocaleString() + ); + console.log( + "Price of 1 token A....$" + + tokenAPrice + + "\t one token in native decimals: " + + (1 * 10 ** tokenADecimals).toLocaleString() + ); + console.log( + "Price of 1 token B....$" + + tokenBPrice + + "\t one token in native decimals: " + + (1 * 10 ** tokenBDecimals).toLocaleString() + ); + console.log(""); + } + let oracles: Oracles = { + wsolOracle: wsolPythOracle, + wsolDecimals: wsolDecimals, + usdcOracle: usdcPythOracle, + usdcDecimals: usdcDecimals, + tokenAOracle: tokenAPythOracle, + tokenADecimals: tokenADecimals, + tokenBOracle: tokenBPythOracle, + tokenBDecimals: tokenBDecimals, + wsolPrice: wsolPrice, + usdcPrice: usdcPrice, + tokenAPrice: tokenAPrice, + tokenBPrice: tokenBPrice, + }; + return oracles; +}; diff --git a/tests/utils/tools.ts b/tests/utils/tools.ts new file mode 100644 index 000000000..0ddcbad6b --- /dev/null +++ b/tests/utils/tools.ts @@ -0,0 +1,78 @@ +/** + * Function to print bytes from a Buffer in groups with column labels and color highlighting for non-zero values + * @param buffer - The Buffer to process + * @param groupLength - The number of bytes in each group, usually 8 or 16 + * @param totalLength - The total number of bytes to process + * @param skipEmptyRows - If a row is all-zero, it will not print + */ +export const printBufferGroups = ( + buffer: Buffer, + groupLength: number, + totalLength: number, + skipEmptyRows: boolean = true +) => { + // Print the column headers + let columnHeader = " |"; + for (let col = 0; col < groupLength; col++) { + if (col < groupLength - 1) { + columnHeader += col.toString().padStart(3, " ").padEnd(6, " "); + } else { + // No end padding for the last column + columnHeader += col.toString().padStart(3, " "); + } + } + console.log(columnHeader); + + // Function to calculate RGB color based on row index + const calculateGradientColor = (startIndex) => { + const maxIndex = 255 * 3; + const normalizedIndex = (startIndex % maxIndex); + + let r = 0, g = 0, b = 0; + + if (normalizedIndex < 255) { + b = 255; + g = normalizedIndex; + } else if (normalizedIndex < 510) { + g = 255; + b = 510 - normalizedIndex; + } else { + g = 765 - normalizedIndex; + r = normalizedIndex - 510; + } + + return `\x1b[38;2;${r};${g};${b}m`; + }; + + // Print the buffer content + for (let i = 0; i < totalLength; i += groupLength) { + let group = []; + let allZero = true; + + for (let j = 0; j < groupLength; j++) { + let value = buffer[i + j]; + let valueStr = + value !== undefined ? value.toString().padStart(3, " ") : " "; + if (value !== 0) { + allZero = false; + } + if (value !== 0 && value !== undefined) { + // Apply red color to non-zero values + group.push(`\x1b[31m${valueStr}\x1b[0m`); + } else { + group.push(valueStr); + } + } + + // Skip printing if the entire group is zero + if (!allZero || !skipEmptyRows) { + const color = calculateGradientColor(i); + const label = `${i.toString().padStart(3, " ")}-${(i + groupLength - 1) + .toString() + .padStart(3, " ")}`; + console.log( + `${color}${label}\x1b[0m | ${group.join(" | ")}` + ); + } + } +}; diff --git a/tests/utils/types.ts b/tests/utils/types.ts new file mode 100644 index 000000000..078dc781a --- /dev/null +++ b/tests/utils/types.ts @@ -0,0 +1,110 @@ +import { bigNumberToWrappedI80F48, WrappedI80F48 } from "@mrgnlabs/mrgn-common"; +import { PublicKey } from "@solana/web3.js"; + +import BN from "bn.js"; + +export const I80F48_ZERO = bigNumberToWrappedI80F48(0); +export const I80F48_ONE = bigNumberToWrappedI80F48(1); + +export type RiskTier = { collateral: {} } | { isolated: {} }; + +export type OperationalState = + | { paused: {} } + | { operational: {} } + | { reduceOnly: {} }; + +export type OracleSetup = + | { none: {} } + | { pythLegacy: {} } + | { switchboardV2: {} } + | { pythPushOracle: {} }; + +export type BankConfig = { + assetWeightInit: WrappedI80F48; + assetWeightMaint: WrappedI80F48; + + liabilityWeightInit: WrappedI80F48; + liabilityWeightMain: WrappedI80F48; + + depositLimit: BN; + interestRateConfig: InterestRateConfig; + + /** Paused = 0, Operational = 1, ReduceOnly = 2 */ + operationalState: OperationalState; + + /** None = 0, PythLegacy = 1, SwitchboardV2 = 2, PythPushOracle =3 */ + oracleSetup: OracleSetup; + oracleKey: PublicKey; + + borrowLimit: BN; + /** Collateral = 0, Isolated = 1 */ + riskTier: RiskTier; + totalAssetValueInitLimit: BN; + oracleMaxAge: number; +}; + +/** + * The default bank config has + * * all weights are 1 + * * state = operational, risk tier = collateral + * * uses the given oracle, assumes it's = pythLegacy + * * 1_000_000_000 deposit/borrow limit + * * 100_000_000_000 total asset value limit + * @returns + */ +export const defaultBankConfig = (oracleKey: PublicKey) => { + let config: BankConfig = { + assetWeightInit: I80F48_ONE, + assetWeightMaint: I80F48_ONE, + liabilityWeightInit: I80F48_ONE, + liabilityWeightMain: I80F48_ONE, + depositLimit: new BN(1_000_000_000), + interestRateConfig: defaultInterestRateConfig(), + operationalState: { + operational: undefined, + }, + oracleSetup: { + pythLegacy: undefined, + }, + oracleKey: oracleKey, + borrowLimit: new BN(1_000_000_000), + riskTier: { + collateral: undefined, + }, + totalAssetValueInitLimit: new BN(100_000_000_000), + oracleMaxAge: 100, + }; + return config; +}; + +export type InterestRateConfig = { + optimalUtilizationRate: WrappedI80F48; + plateauInterestRate: WrappedI80F48; + maxInterestRate: WrappedI80F48; + + insuranceFeeFixedApr: WrappedI80F48; + insuranceIrFee: WrappedI80F48; + protocolFixedFeeApr: WrappedI80F48; + protocolIrFee: WrappedI80F48; +}; + +/** + * The default interest config has + * * optimalUtilizationRate = .5 + * * plateauInterestRate = .6 + * * maxInterestRate = 3 + * * All others values = 0 + * @returns + */ +export const defaultInterestRateConfig = () => { + let config: InterestRateConfig = { + optimalUtilizationRate: bigNumberToWrappedI80F48(0.5), + plateauInterestRate: bigNumberToWrappedI80F48(0.6), + maxInterestRate: bigNumberToWrappedI80F48(3), + insuranceFeeFixedApr: I80F48_ZERO, + insuranceIrFee: I80F48_ZERO, + protocolFixedFeeApr: I80F48_ZERO, + protocolIrFee: I80F48_ZERO, + }; + return config; +}; diff --git a/tsconfig.json b/tsconfig.json index cd5d2e3d0..7c4018468 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,9 +2,10 @@ "compilerOptions": { "types": ["mocha", "chai"], "typeRoots": ["./node_modules/@types"], - "lib": ["es2015"], + "lib": ["ES2022"], "module": "commonjs", - "target": "es6", - "esModuleInterop": true + "target": "ES2022", + "esModuleInterop": true, + "sourceMap": true, } } diff --git a/yarn.lock b/yarn.lock index ec483af3e..7590eb8dd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,92 +2,543 @@ # yarn lockfile v1 -"@babel/runtime@^7.12.5", "@babel/runtime@^7.17.2": - version "7.20.6" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.20.6.tgz#facf4879bfed9b5326326273a64220f099b0fce3" - integrity sha512-Q+8MqP7TiHMWzSfwiJwXCjyf4GYA4Dgw3emg/7xmwsdLJOZUp+nMqcOwOzzYheuM1rhDu8FSj2l0aoMygEuXuA== - dependencies: - regenerator-runtime "^0.13.11" - -"@noble/ed25519@^1.7.0": - version "1.7.1" - resolved "https://registry.yarnpkg.com/@noble/ed25519/-/ed25519-1.7.1.tgz#6899660f6fbb97798a6fbd227227c4589a454724" - integrity sha512-Rk4SkJFaXZiznFyC/t77Q0NKS4FL7TLJJsVG2V2oiEq3kJVeTdxysEe/yRWSpnWMe808XRDJ+VFh5pt/FN5plw== - -"@noble/hashes@^1.1.2": - version "1.1.4" - resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.1.4.tgz#2611ebf5764c1bf754da7c7794de4fb30512336d" - integrity sha512-+PYsVPrTSqtVjatKt2A/Proukn2Yrz61OBThOCKErc5w2/r1Fh37vbDv0Eah7pyNltrmacjwTvdw3JoR+WE4TA== - -"@noble/secp256k1@^1.6.3": - version "1.7.0" - resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-1.7.0.tgz#d15357f7c227e751d90aa06b05a0e5cf993ba8c1" - integrity sha512-kbacwGSsH/CTout0ZnZWxnW1B+jH/7r/WAAKLBtrRJ/+CUH7lgmQzl3GTrQua3SGKWNSDsS6lmjnDpIJ5Dxyaw== +"@babel/runtime@^7.12.5", "@babel/runtime@^7.24.8": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.25.0.tgz#3af9a91c1b739c569d5d80cc917280919c544ecb" + integrity sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw== + dependencies: + regenerator-runtime "^0.14.0" + +"@coral-xyz/anchor-errors@^0.30.1": + version "0.30.1" + resolved "https://registry.yarnpkg.com/@coral-xyz/anchor-errors/-/anchor-errors-0.30.1.tgz#bdfd3a353131345244546876eb4afc0e125bec30" + integrity sha512-9Mkradf5yS5xiLWrl9WrpjqOrAV+/W2RQHDlbnAZBivoGpOs1ECjoDCkVk4aRG8ZdiFiB8zQEVlxf+8fKkmSfQ== + +"@coral-xyz/anchor@=0.30.1", "@coral-xyz/anchor@^0.30.1": + version "0.30.1" + resolved "https://registry.yarnpkg.com/@coral-xyz/anchor/-/anchor-0.30.1.tgz#17f3e9134c28cd0ea83574c6bab4e410bcecec5d" + integrity sha512-gDXFoF5oHgpriXAaLpxyWBHdCs8Awgf/gLHIo6crv7Aqm937CNdY+x+6hoj7QR5vaJV7MxWSQ0NGFzL3kPbWEQ== + dependencies: + "@coral-xyz/anchor-errors" "^0.30.1" + "@coral-xyz/borsh" "^0.30.1" + "@noble/hashes" "^1.3.1" + "@solana/web3.js" "^1.68.0" + bn.js "^5.1.2" + bs58 "^4.0.1" + buffer-layout "^1.2.2" + camelcase "^6.3.0" + cross-fetch "^3.1.5" + crypto-hash "^1.3.0" + eventemitter3 "^4.0.7" + pako "^2.0.3" + snake-case "^3.0.4" + superstruct "^0.15.4" + toml "^3.0.0" -"@project-serum/anchor@^0.25.0": - version "0.25.0" - resolved "https://registry.yarnpkg.com/@project-serum/anchor/-/anchor-0.25.0.tgz#88ee4843336005cf5a64c80636ce626f0996f503" - integrity sha512-E6A5Y/ijqpfMJ5psJvbw0kVTzLZFUcOFgs6eSM2M2iWE1lVRF18T6hWZVNl6zqZsoz98jgnNHtVGJMs+ds9A7A== +"@coral-xyz/anchor@^0.29.0": + version "0.29.0" + resolved "https://registry.yarnpkg.com/@coral-xyz/anchor/-/anchor-0.29.0.tgz#bd0be95bedfb30a381c3e676e5926124c310ff12" + integrity sha512-eny6QNG0WOwqV0zQ7cs/b1tIuzZGmP7U7EcH+ogt4Gdbl8HDmIYVMh/9aTmYZPaFWjtUaI8qSn73uYEXWfATdA== dependencies: - "@project-serum/borsh" "^0.2.5" - "@solana/web3.js" "^1.36.0" - base64-js "^1.5.1" + "@coral-xyz/borsh" "^0.29.0" + "@noble/hashes" "^1.3.1" + "@solana/web3.js" "^1.68.0" bn.js "^5.1.2" bs58 "^4.0.1" buffer-layout "^1.2.2" - camelcase "^5.3.1" + camelcase "^6.3.0" cross-fetch "^3.1.5" crypto-hash "^1.3.0" eventemitter3 "^4.0.7" - js-sha256 "^0.9.0" pako "^2.0.3" snake-case "^3.0.4" superstruct "^0.15.4" toml "^3.0.0" -"@project-serum/borsh@^0.2.5": - version "0.2.5" - resolved "https://registry.yarnpkg.com/@project-serum/borsh/-/borsh-0.2.5.tgz#6059287aa624ecebbfc0edd35e4c28ff987d8663" - integrity sha512-UmeUkUoKdQ7rhx6Leve1SssMR/Ghv8qrEiyywyxSWg7ooV7StdpPBhciiy5eB3T0qU1BXvdRNC8TdrkxK7WC5Q== +"@coral-xyz/borsh@^0.29.0": + version "0.29.0" + resolved "https://registry.yarnpkg.com/@coral-xyz/borsh/-/borsh-0.29.0.tgz#79f7045df2ef66da8006d47f5399c7190363e71f" + integrity sha512-s7VFVa3a0oqpkuRloWVPdCK7hMbAMY270geZOGfCnaqexrP5dTIpbEHL33req6IYPPJ0hYa71cdvJ1h6V55/oQ== + dependencies: + bn.js "^5.1.2" + buffer-layout "^1.2.0" + +"@coral-xyz/borsh@^0.30.1": + version "0.30.1" + resolved "https://registry.yarnpkg.com/@coral-xyz/borsh/-/borsh-0.30.1.tgz#869d8833abe65685c72e9199b8688477a4f6b0e3" + integrity sha512-aaxswpPrCFKl8vZTbxLssA2RvwX2zmKLlRCIktJOwW+VpVwYtXRtlWiIP+c2pPRKneiTiWCN2GEMSH9j1zTlWQ== dependencies: bn.js "^5.1.2" buffer-layout "^1.2.0" -"@pythnetwork/client@^2.9.0": - version "2.9.0" - resolved "https://registry.yarnpkg.com/@pythnetwork/client/-/client-2.9.0.tgz#96cf9f56d2144139758dc49ca6c981f87ce950e2" - integrity sha512-2CyDmTwPWW+JCQgRKUpwMR/31oiLWH6I3GA0h2ZXIcbt/hWxcr5TXyKlWuyi+l+jh73WWh88gq8NXLoIgRcvkA== +"@coral-xyz/spl-token@^0.30.1": + version "0.30.1" + resolved "https://registry.yarnpkg.com/@coral-xyz/spl-token/-/spl-token-0.30.1.tgz#05223b2416fe46452777d3217a99cbe3fa2ff98b" + integrity sha512-3YGSkGergnfjr4FyWAiZxPdZbI+cIrGl407W/L541WtKUlNWykKgQlIpXvBctGeZ3s5QpiCr8KBY1Z8dblwCmQ== + dependencies: + "@coral-xyz/anchor" "=0.30.1" + "@native-to-anchor/buffer-layout" "=0.1.0" + +"@cspotcode/source-map-support@^0.8.0": + version "0.8.1" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" + integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== + dependencies: + "@jridgewell/trace-mapping" "0.3.9" + +"@grpc/grpc-js@^1.8.13": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.11.1.tgz#a92f33e98f1959feffcd1b25a33b113d2c977b70" + integrity sha512-gyt/WayZrVPH2w/UTLansS7F9Nwld472JxxaETamrM8HNlsa+jSLNyKAZmhxI2Me4c3mQHFiS1wWHDY1g1Kthw== + dependencies: + "@grpc/proto-loader" "^0.7.13" + "@js-sdsl/ordered-map" "^4.4.2" + +"@grpc/proto-loader@^0.7.13": + version "0.7.13" + resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.7.13.tgz#f6a44b2b7c9f7b609f5748c6eac2d420e37670cf" + integrity sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw== + dependencies: + lodash.camelcase "^4.3.0" + long "^5.0.0" + protobufjs "^7.2.5" + yargs "^17.7.2" + +"@jridgewell/resolve-uri@^3.0.3": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + +"@jridgewell/sourcemap-codec@^1.4.10": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" + integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== + +"@jridgewell/trace-mapping@0.3.9": + version "0.3.9" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" + integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@js-sdsl/ordered-map@^4.4.2": + version "4.4.2" + resolved "https://registry.yarnpkg.com/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz#9299f82874bab9e4c7f9c48d865becbfe8d6907c" + integrity sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw== + +"@mrgnlabs/marginfi-client-v2@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@mrgnlabs/marginfi-client-v2/-/marginfi-client-v2-3.1.0.tgz#f380b63aa5ec4fe9f467e3711c5410970c907403" + integrity sha512-XXq+7iltsMe1BvboG3SQb1xjDoJq1W24eNZd1r3xor54GoeGxjVIvvrSNAKlU0CyzlqzuN1EosBBLmnKSuC+8A== + dependencies: + "@coral-xyz/anchor" "^0.30.1" + "@mrgnlabs/mrgn-common" "*" + "@pythnetwork/pyth-solana-receiver" "^0.8.0" + "@solana/wallet-adapter-base" "^0.9.23" + "@solana/web3.js" "^1.93.2" + bignumber.js "^9.1.2" + borsh "^2.0.0" + bs58 "^6.0.0" + decimal.js "^10.4.3" + superstruct "^1.0.4" + +"@mrgnlabs/mrgn-common@*", "@mrgnlabs/mrgn-common@^1.7.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@mrgnlabs/mrgn-common/-/mrgn-common-1.7.0.tgz#0a40b7696057ee4119f4fe3950ead11623085545" + integrity sha512-vDeVmcSRB4tAXDZPNTrzlOIhWQFk+CD5akuBl6vaULwRrxMwkSmOxvkgnXHdxXvKgTH9CfU/0exkevOc4VXslQ== + dependencies: + "@coral-xyz/anchor" "^0.30.1" + "@solana/buffer-layout-utils" "^0.2.0" + "@solana/wallet-adapter-base" "^0.9.23" + "@solana/web3.js" "^1.93.2" + bignumber.js "^9.1.2" + bs58 "^6.0.0" + decimal.js "^10.4.3" + numeral "^2.0.6" + superstruct "^1.0.4" + +"@native-to-anchor/buffer-layout@=0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@native-to-anchor/buffer-layout/-/buffer-layout-0.1.0.tgz#ff0cb66341bc820b8ee73bb1d1d43bae7e3554b0" + integrity sha512-7Ykz9KRAm53XqHj5blDUKPX+OXAPO4GZBW4zJhfHGIAbzmqsUFh9kMqR66Bak3mp6wyv1OVTwSr8ZGHKswPxDg== + dependencies: + "@solana/buffer-layout" "=4.0.0" + "@solana/buffer-layout-utils" "=0.2.0" + +"@noble/curves@^1.0.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.5.0.tgz#7a9b9b507065d516e6dce275a1e31db8d2a100dd" + integrity sha512-J5EKamIHnKPyClwVrzmaf5wSdQXgdHcPZIZLu3bwnbeCx8/7NPK5q2ZBWF+5FvYGByjiQQsJYX6jfgB2wDPn3A== + dependencies: + "@noble/hashes" "1.4.0" + +"@noble/curves@^1.4.2": + version "1.4.2" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.4.2.tgz#40309198c76ed71bc6dbf7ba24e81ceb4d0d1fe9" + integrity sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw== + dependencies: + "@noble/hashes" "1.4.0" + +"@noble/ed25519@^1.7.1": + version "1.7.3" + resolved "https://registry.yarnpkg.com/@noble/ed25519/-/ed25519-1.7.3.tgz#57e1677bf6885354b466c38e2b620c62f45a7123" + integrity sha512-iR8GBkDt0Q3GyaVcIu7mSsVIqnFbkbRzGLWlvhwunacoLwt4J3swfKhfaM6rN6WY+TBGoYT1GtT1mIh2/jGbRQ== + +"@noble/hashes@1.4.0", "@noble/hashes@^1.3.0", "@noble/hashes@^1.3.1", "@noble/hashes@^1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.4.0.tgz#45814aa329f30e4fe0ba49426f49dfccdd066426" + integrity sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg== + +"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" + integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ== + +"@protobufjs/base64@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735" + integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== + +"@protobufjs/codegen@^2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb" + integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== + +"@protobufjs/eventemitter@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70" + integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q== + +"@protobufjs/fetch@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45" + integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ== + dependencies: + "@protobufjs/aspromise" "^1.1.1" + "@protobufjs/inquire" "^1.1.0" + +"@protobufjs/float@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" + integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ== + +"@protobufjs/inquire@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089" + integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q== + +"@protobufjs/path@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d" + integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA== + +"@protobufjs/pool@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54" + integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw== + +"@protobufjs/utf8@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" + integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== + +"@pythnetwork/price-service-sdk@>=1.6.0": + version "1.7.1" + resolved "https://registry.yarnpkg.com/@pythnetwork/price-service-sdk/-/price-service-sdk-1.7.1.tgz#dbfc8a8c2189f526346c1f79ec3995e89b690700" + integrity sha512-xr2boVXTyv1KUt/c6llUTfbv2jpud99pWlMJbFaHGUBoygQsByuy7WbjIJKZ+0Blg1itLZl0Lp/pJGGg8SdJoQ== + dependencies: + bn.js "^5.2.1" + +"@pythnetwork/pyth-solana-receiver@^0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@pythnetwork/pyth-solana-receiver/-/pyth-solana-receiver-0.8.0.tgz#d7bf3c5c97a0f0eab8ac19f53b11664117e1152d" + integrity sha512-5lhLtggAqsiHtffTPM8vcKJmhBdxzidBmiNNUlqPyg9XmhZ4Z+roY0dfzluEoX5xer9rEA1ThsBpX0bG1DRIGA== + dependencies: + "@coral-xyz/anchor" "^0.29.0" + "@noble/hashes" "^1.4.0" + "@pythnetwork/price-service-sdk" ">=1.6.0" + "@pythnetwork/solana-utils" "*" + "@solana/web3.js" "^1.90.0" + +"@pythnetwork/solana-utils@*": + version "0.4.2" + resolved "https://registry.yarnpkg.com/@pythnetwork/solana-utils/-/solana-utils-0.4.2.tgz#3e220eed518c02ad702ebb023488afd7c5649a87" + integrity sha512-hKo7Bcs/kDWA5Fnqhg9zJSB94NMoUDIDjHjSi/uvZOzwizISUQI6oY3LWd2CXzNh4f8djjY2BS5iNHaM4cm8Bw== + dependencies: + "@coral-xyz/anchor" "^0.29.0" + "@solana/web3.js" "^1.90.0" + bs58 "^5.0.0" + jito-ts "^3.0.1" + +"@solana/buffer-layout-utils@=0.2.0", "@solana/buffer-layout-utils@^0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@solana/buffer-layout-utils/-/buffer-layout-utils-0.2.0.tgz#b45a6cab3293a2eb7597cceb474f229889d875ca" + integrity sha512-szG4sxgJGktbuZYDg2FfNmkMi0DYQoVjN2h7ta1W1hPrwzarcFLBq9UpX1UjNXsNpT9dn+chgprtWGioUAr4/g== dependencies: - buffer "^6.0.1" + "@solana/buffer-layout" "^4.0.0" + "@solana/web3.js" "^1.32.0" + bigint-buffer "^1.1.5" + bignumber.js "^9.0.1" -"@solana/buffer-layout@^4.0.0": +"@solana/buffer-layout@=4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@solana/buffer-layout/-/buffer-layout-4.0.0.tgz#75b1b11adc487234821c81dfae3119b73a5fd734" + integrity sha512-lR0EMP2HC3+Mxwd4YcnZb0smnaDw7Bl2IQWZiTevRH5ZZBZn6VRWn3/92E3qdU4SSImJkA6IDHawOHAnx/qUvQ== + dependencies: + buffer "~6.0.3" + +"@solana/buffer-layout@^4.0.0", "@solana/buffer-layout@^4.0.1": version "4.0.1" resolved "https://registry.yarnpkg.com/@solana/buffer-layout/-/buffer-layout-4.0.1.tgz#b996235eaec15b1e0b5092a8ed6028df77fa6c15" integrity sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA== dependencies: buffer "~6.0.3" -"@solana/web3.js@^1.36.0": - version "1.70.1" - resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.70.1.tgz#4a2df47cc32a0f67be5161e772b2ceb6512281fa" - integrity sha512-AnaqCF1cJ3w7d0yhvLGAKAcRI+n5o+ursQihhoTe4cUh8/9d4gbT73SoHYElS7e67OtAgLmSfbcC5hcOAgdvnQ== +"@solana/codecs-core@2.0.0-preview.2": + version "2.0.0-preview.2" + resolved "https://registry.yarnpkg.com/@solana/codecs-core/-/codecs-core-2.0.0-preview.2.tgz#689784d032fbc1fedbde40bb25d76cdcecf6553b" + integrity sha512-gLhCJXieSCrAU7acUJjbXl+IbGnqovvxQLlimztPoGgfLQ1wFYu+XJswrEVQqknZYK1pgxpxH3rZ+OKFs0ndQg== + dependencies: + "@solana/errors" "2.0.0-preview.2" + +"@solana/codecs-core@2.0.0-preview.4": + version "2.0.0-preview.4" + resolved "https://registry.yarnpkg.com/@solana/codecs-core/-/codecs-core-2.0.0-preview.4.tgz#770826105f2f884110a21662573e7a2014654324" + integrity sha512-A0VVuDDA5kNKZUinOqHxJQK32aKTucaVbvn31YenGzHX1gPqq+SOnFwgaEY6pq4XEopSmaK16w938ZQS8IvCnw== + dependencies: + "@solana/errors" "2.0.0-preview.4" + +"@solana/codecs-data-structures@2.0.0-preview.2": + version "2.0.0-preview.2" + resolved "https://registry.yarnpkg.com/@solana/codecs-data-structures/-/codecs-data-structures-2.0.0-preview.2.tgz#e82cb1b6d154fa636cd5c8953ff3f32959cc0370" + integrity sha512-Xf5vIfromOZo94Q8HbR04TbgTwzigqrKII0GjYr21K7rb3nba4hUW2ir8kguY7HWFBcjHGlU5x3MevKBOLp3Zg== + dependencies: + "@solana/codecs-core" "2.0.0-preview.2" + "@solana/codecs-numbers" "2.0.0-preview.2" + "@solana/errors" "2.0.0-preview.2" + +"@solana/codecs-data-structures@2.0.0-preview.4": + version "2.0.0-preview.4" + resolved "https://registry.yarnpkg.com/@solana/codecs-data-structures/-/codecs-data-structures-2.0.0-preview.4.tgz#f8a2470982a9792334737ea64000ccbdff287247" + integrity sha512-nt2k2eTeyzlI/ccutPcG36M/J8NAYfxBPI9h/nQjgJ+M+IgOKi31JV8StDDlG/1XvY0zyqugV3I0r3KAbZRJpA== + dependencies: + "@solana/codecs-core" "2.0.0-preview.4" + "@solana/codecs-numbers" "2.0.0-preview.4" + "@solana/errors" "2.0.0-preview.4" + +"@solana/codecs-numbers@2.0.0-preview.2": + version "2.0.0-preview.2" + resolved "https://registry.yarnpkg.com/@solana/codecs-numbers/-/codecs-numbers-2.0.0-preview.2.tgz#56995c27396cd8ee3bae8bd055363891b630bbd0" + integrity sha512-aLZnDTf43z4qOnpTcDsUVy1Ci9im1Md8thWipSWbE+WM9ojZAx528oAql+Cv8M8N+6ALKwgVRhPZkto6E59ARw== + dependencies: + "@solana/codecs-core" "2.0.0-preview.2" + "@solana/errors" "2.0.0-preview.2" + +"@solana/codecs-numbers@2.0.0-preview.4": + version "2.0.0-preview.4" + resolved "https://registry.yarnpkg.com/@solana/codecs-numbers/-/codecs-numbers-2.0.0-preview.4.tgz#6a53b456bb7866f252d8c032c81a92651e150f66" + integrity sha512-Q061rLtMadsO7uxpguT+Z7G4UHnjQ6moVIxAQxR58nLxDPCC7MB1Pk106/Z7NDhDLHTcd18uO6DZ7ajHZEn2XQ== + dependencies: + "@solana/codecs-core" "2.0.0-preview.4" + "@solana/errors" "2.0.0-preview.4" + +"@solana/codecs-strings@2.0.0-preview.2": + version "2.0.0-preview.2" + resolved "https://registry.yarnpkg.com/@solana/codecs-strings/-/codecs-strings-2.0.0-preview.2.tgz#8bd01a4e48614d5289d72d743c3e81305d445c46" + integrity sha512-EgBwY+lIaHHgMJIqVOGHfIfpdmmUDNoNO/GAUGeFPf+q0dF+DtwhJPEMShhzh64X2MeCZcmSO6Kinx0Bvmmz2g== + dependencies: + "@solana/codecs-core" "2.0.0-preview.2" + "@solana/codecs-numbers" "2.0.0-preview.2" + "@solana/errors" "2.0.0-preview.2" + +"@solana/codecs-strings@2.0.0-preview.4": + version "2.0.0-preview.4" + resolved "https://registry.yarnpkg.com/@solana/codecs-strings/-/codecs-strings-2.0.0-preview.4.tgz#4d06bb722a55a5d04598d362021bfab4bd446760" + integrity sha512-YDbsQePRWm+xnrfS64losSGRg8Wb76cjK1K6qfR8LPmdwIC3787x9uW5/E4icl/k+9nwgbIRXZ65lpF+ucZUnw== + dependencies: + "@solana/codecs-core" "2.0.0-preview.4" + "@solana/codecs-numbers" "2.0.0-preview.4" + "@solana/errors" "2.0.0-preview.4" + +"@solana/codecs@2.0.0-preview.2": + version "2.0.0-preview.2" + resolved "https://registry.yarnpkg.com/@solana/codecs/-/codecs-2.0.0-preview.2.tgz#d6615fec98f423166fb89409f9a4ad5b74c10935" + integrity sha512-4HHzCD5+pOSmSB71X6w9ptweV48Zj1Vqhe732+pcAQ2cMNnN0gMPMdDq7j3YwaZDZ7yrILVV/3+HTnfT77t2yA== + dependencies: + "@solana/codecs-core" "2.0.0-preview.2" + "@solana/codecs-data-structures" "2.0.0-preview.2" + "@solana/codecs-numbers" "2.0.0-preview.2" + "@solana/codecs-strings" "2.0.0-preview.2" + "@solana/options" "2.0.0-preview.2" + +"@solana/codecs@2.0.0-preview.4": + version "2.0.0-preview.4" + resolved "https://registry.yarnpkg.com/@solana/codecs/-/codecs-2.0.0-preview.4.tgz#a1923cc78a6f64ebe656c7ec6335eb6b70405b22" + integrity sha512-gLMupqI4i+G4uPi2SGF/Tc1aXcviZF2ybC81x7Q/fARamNSgNOCUUoSCg9nWu1Gid6+UhA7LH80sWI8XjKaRog== + dependencies: + "@solana/codecs-core" "2.0.0-preview.4" + "@solana/codecs-data-structures" "2.0.0-preview.4" + "@solana/codecs-numbers" "2.0.0-preview.4" + "@solana/codecs-strings" "2.0.0-preview.4" + "@solana/options" "2.0.0-preview.4" + +"@solana/errors@2.0.0-preview.2": + version "2.0.0-preview.2" + resolved "https://registry.yarnpkg.com/@solana/errors/-/errors-2.0.0-preview.2.tgz#e0ea8b008c5c02528d5855bc1903e5e9bbec322e" + integrity sha512-H2DZ1l3iYF5Rp5pPbJpmmtCauWeQXRJapkDg8epQ8BJ7cA2Ut/QEtC3CMmw/iMTcuS6uemFNLcWvlOfoQhvQuA== + dependencies: + chalk "^5.3.0" + commander "^12.0.0" + +"@solana/errors@2.0.0-preview.4": + version "2.0.0-preview.4" + resolved "https://registry.yarnpkg.com/@solana/errors/-/errors-2.0.0-preview.4.tgz#056ba76b6dd900dafa70117311bec3aef0f5250b" + integrity sha512-kadtlbRv2LCWr8A9V22On15Us7Nn8BvqNaOB4hXsTB3O0fU40D1ru2l+cReqLcRPij4znqlRzW9Xi0m6J5DIhA== + dependencies: + chalk "^5.3.0" + commander "^12.1.0" + +"@solana/options@2.0.0-preview.2": + version "2.0.0-preview.2" + resolved "https://registry.yarnpkg.com/@solana/options/-/options-2.0.0-preview.2.tgz#13ff008bf43a5056ef9a091dc7bb3f39321e867e" + integrity sha512-FAHqEeH0cVsUOTzjl5OfUBw2cyT8d5Oekx4xcn5hn+NyPAfQJgM3CEThzgRD6Q/4mM5pVUnND3oK/Mt1RzSE/w== + dependencies: + "@solana/codecs-core" "2.0.0-preview.2" + "@solana/codecs-numbers" "2.0.0-preview.2" + +"@solana/options@2.0.0-preview.4": + version "2.0.0-preview.4" + resolved "https://registry.yarnpkg.com/@solana/options/-/options-2.0.0-preview.4.tgz#212d35d1da87c7efb13de4d3569ad9eb070f013d" + integrity sha512-tv2O/Frxql/wSe3jbzi5nVicIWIus/BftH+5ZR+r9r3FO0/htEllZS5Q9XdbmSboHu+St87584JXeDx3xm4jaA== + dependencies: + "@solana/codecs-core" "2.0.0-preview.4" + "@solana/codecs-data-structures" "2.0.0-preview.4" + "@solana/codecs-numbers" "2.0.0-preview.4" + "@solana/codecs-strings" "2.0.0-preview.4" + "@solana/errors" "2.0.0-preview.4" + +"@solana/spl-token-group@^0.0.5": + version "0.0.5" + resolved "https://registry.yarnpkg.com/@solana/spl-token-group/-/spl-token-group-0.0.5.tgz#f955dcca782031c85e862b2b46878d1bb02db6c2" + integrity sha512-CLJnWEcdoUBpQJfx9WEbX3h6nTdNiUzswfFdkABUik7HVwSNA98u5AYvBVK2H93d9PGMOHAak2lHW9xr+zAJGQ== + dependencies: + "@solana/codecs" "2.0.0-preview.4" + "@solana/spl-type-length-value" "0.1.0" + +"@solana/spl-token-metadata@^0.1.3": + version "0.1.4" + resolved "https://registry.yarnpkg.com/@solana/spl-token-metadata/-/spl-token-metadata-0.1.4.tgz#5cdc3b857a8c4a6877df24e24a8648c4132d22ba" + integrity sha512-N3gZ8DlW6NWDV28+vCCDJoTqaCZiF/jDUnk3o8GRkAFzHObiR60Bs1gXHBa8zCPdvOwiG6Z3dg5pg7+RW6XNsQ== + dependencies: + "@solana/codecs" "2.0.0-preview.2" + "@solana/spl-type-length-value" "0.1.0" + +"@solana/spl-token@^0.4.8": + version "0.4.8" + resolved "https://registry.yarnpkg.com/@solana/spl-token/-/spl-token-0.4.8.tgz#a84e4131af957fa9fbd2727e5fc45dfbf9083586" + integrity sha512-RO0JD9vPRi4LsAbMUdNbDJ5/cv2z11MGhtAvFeRzT4+hAGE/FUzRi0tkkWtuCfSIU3twC6CtmAihRp/+XXjWsA== + dependencies: + "@solana/buffer-layout" "^4.0.0" + "@solana/buffer-layout-utils" "^0.2.0" + "@solana/spl-token-group" "^0.0.5" + "@solana/spl-token-metadata" "^0.1.3" + buffer "^6.0.3" + +"@solana/spl-type-length-value@0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@solana/spl-type-length-value/-/spl-type-length-value-0.1.0.tgz#b5930cf6c6d8f50c7ff2a70463728a4637a2f26b" + integrity sha512-JBMGB0oR4lPttOZ5XiUGyvylwLQjt1CPJa6qQ5oM+MBCndfjz2TKKkw0eATlLLcYmq1jBVsNlJ2cD6ns2GR7lA== + dependencies: + buffer "^6.0.3" + +"@solana/wallet-adapter-base@^0.9.23": + version "0.9.23" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-base/-/wallet-adapter-base-0.9.23.tgz#3b17c28afd44e173f44f658bf9700fd637e12a11" + integrity sha512-apqMuYwFp1jFi55NxDfvXUX2x1T0Zh07MxhZ/nCCTGys5raSfYUh82zen2BLv8BSDj/JxZ2P/s7jrQZGrX8uAw== + dependencies: + "@solana/wallet-standard-features" "^1.1.0" + "@wallet-standard/base" "^1.0.1" + "@wallet-standard/features" "^1.0.3" + eventemitter3 "^4.0.7" + +"@solana/wallet-standard-features@^1.1.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@solana/wallet-standard-features/-/wallet-standard-features-1.2.0.tgz#be8b3824abf5ebcfeaa7298445bf53f76a27c935" + integrity sha512-tUd9srDLkRpe1BYg7we+c4UhRQkq+XQWswsr/L1xfGmoRDF47BPSXf4zE7ZU2GRBGvxtGt7lwJVAufQyQYhxTQ== + dependencies: + "@wallet-standard/base" "^1.0.1" + "@wallet-standard/features" "^1.0.3" + +"@solana/web3.js@^1.32.0", "@solana/web3.js@^1.68.0", "@solana/web3.js@^1.90.0", "@solana/web3.js@^1.93.2", "@solana/web3.js@^1.95.2": + version "1.95.2" + resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.95.2.tgz#6f8a0362fa75886a21550dbec49aad54481463a6" + integrity sha512-SjlHp0G4qhuhkQQc+YXdGkI8EerCqwxvgytMgBpzMUQTafrkNant3e7pgilBGgjy/iM40ICvWBLgASTPMrQU7w== + dependencies: + "@babel/runtime" "^7.24.8" + "@noble/curves" "^1.4.2" + "@noble/hashes" "^1.4.0" + "@solana/buffer-layout" "^4.0.1" + agentkeepalive "^4.5.0" + bigint-buffer "^1.1.5" + bn.js "^5.2.1" + borsh "^0.7.0" + bs58 "^4.0.1" + buffer "6.0.3" + fast-stable-stringify "^1.0.0" + jayson "^4.1.1" + node-fetch "^2.7.0" + rpc-websockets "^9.0.2" + superstruct "^2.0.2" + +"@solana/web3.js@~1.77.3": + version "1.77.4" + resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.77.4.tgz#aad8c44a02ced319493308ef765a2b36a9e9fa8c" + integrity sha512-XdN0Lh4jdY7J8FYMyucxCwzn6Ga2Sr1DHDWRbqVzk7ZPmmpSPOVWHzO67X1cVT+jNi1D6gZi2tgjHgDPuj6e9Q== dependencies: "@babel/runtime" "^7.12.5" - "@noble/ed25519" "^1.7.0" - "@noble/hashes" "^1.1.2" - "@noble/secp256k1" "^1.6.3" + "@noble/curves" "^1.0.0" + "@noble/hashes" "^1.3.0" "@solana/buffer-layout" "^4.0.0" + agentkeepalive "^4.2.1" bigint-buffer "^1.1.5" bn.js "^5.0.0" borsh "^0.7.0" bs58 "^4.0.1" - buffer "6.0.1" + buffer "6.0.3" fast-stable-stringify "^1.0.0" - jayson "^3.4.4" - node-fetch "2" - rpc-websockets "^7.5.0" + jayson "^4.1.0" + node-fetch "^2.6.7" + rpc-websockets "^7.5.1" superstruct "^0.14.2" +"@swc/helpers@^0.5.11": + version "0.5.12" + resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.12.tgz#37aaca95284019eb5d2207101249435659709f4b" + integrity sha512-KMZNXiGibsW9kvZAO1Pam2JPTDBm+KSHMMHWdsyI/1DbIZjT2A6Gy3hblVXUMEDvUAKq+e0vL0X0o54owWji7g== + dependencies: + tslib "^2.4.0" + +"@tsconfig/node10@^1.0.7": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.11.tgz#6ee46400685f130e278128c7b38b7e031ff5b2f2" + integrity sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw== + +"@tsconfig/node12@^1.0.7": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" + integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== + +"@tsconfig/node14@^1.0.0": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" + integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== + +"@tsconfig/node16@^1.0.2": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" + integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== + "@types/bn.js@^5.1.0": version "5.1.1" resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.1.1.tgz#b51e1b55920a4ca26e9285ff79936bbdec910682" @@ -122,11 +573,23 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.13.tgz#dff34f226ec1ac0432ae3b136ec5552bd3b9c0fe" integrity sha512-IASpMGVcWpUsx5xBOrxMj7Bl8lqfuTY7FKAnPmu5cHkfQVWF8GulWS1jbRqA934qZL35xh5xN/+Xe/i26Bod4w== +"@types/node@>=13.7.0": + version "22.3.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.3.0.tgz#7f8da0e2b72c27c4f9bd3cb5ef805209d04d4f9e" + integrity sha512-nrWpWVaDZuaVc5X84xJ0vNrLvomM205oQyLsRt7OHNZbSHslcWsvgFR7O7hire2ZonjLrWBbedmotmIlJDVd6g== + dependencies: + undici-types "~6.18.2" + "@types/node@^12.12.54": version "12.20.55" resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240" integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ== +"@types/uuid@^8.3.4": + version "8.3.4" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.4.tgz#bd86a43617df0594787d38b735f55c805becf1bc" + integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw== + "@types/ws@^7.4.4": version "7.4.7" resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.7.tgz#f7c390a36f7a0679aa69de2d501319f4f8d9b702" @@ -134,10 +597,24 @@ dependencies: "@types/node" "*" -"@ungap/promise-all-settled@1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" - integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== +"@types/ws@^8.2.2": + version "8.5.12" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.12.tgz#619475fe98f35ccca2a2f6c137702d85ec247b7e" + integrity sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ== + dependencies: + "@types/node" "*" + +"@wallet-standard/base@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@wallet-standard/base/-/base-1.0.1.tgz#860dd94d47c9e3c5c43b79d91c6afdbd7a36264e" + integrity sha512-1To3ekMfzhYxe0Yhkpri+Fedq0SYcfrOfJi3vbLjMwF2qiKPjTGLwZkf2C9ftdQmxES+hmxhBzTwF4KgcOwf8w== + +"@wallet-standard/features@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@wallet-standard/features/-/features-1.0.3.tgz#c992876c5e4f7a0672f8869c4146c87e0dfe48c8" + integrity sha512-m8475I6W5LTatTZuUz5JJNK42wFRgkJTB0I9tkruMwfqBF2UN2eomkYNVf9RbrsROelCRzSFmugqjKZBFaubsA== + dependencies: + "@wallet-standard/base" "^1.0.1" JSONStream@^1.3.5: version "1.3.5" @@ -147,10 +624,29 @@ JSONStream@^1.3.5: jsonparse "^1.2.0" through ">=2.2.7 <3" -ansi-colors@4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" - integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== +acorn-walk@^8.1.1: + version "8.3.3" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.3.tgz#9caeac29eefaa0c41e3d4c65137de4d6f34df43e" + integrity sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw== + dependencies: + acorn "^8.11.0" + +acorn@^8.11.0, acorn@^8.4.1: + version "8.12.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" + integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== + +agentkeepalive@^4.2.1, agentkeepalive@^4.3.0, agentkeepalive@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.5.0.tgz#2673ad1389b3c418c5a20c5d7364f93ca04be923" + integrity sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew== + dependencies: + humanize-ms "^1.2.1" + +ansi-colors@^4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" + integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== ansi-regex@^5.0.1: version "5.0.1" @@ -172,6 +668,11 @@ anymatch@~3.1.2: normalize-path "^3.0.0" picomatch "^2.0.4" +arg@^4.1.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== + argparse@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" @@ -199,7 +700,17 @@ base-x@^3.0.2: dependencies: safe-buffer "^5.0.1" -base64-js@^1.3.1, base64-js@^1.5.1: +base-x@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/base-x/-/base-x-4.0.0.tgz#d0e3b7753450c73f8ad2389b5c018a4af7b2224a" + integrity sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw== + +base-x@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/base-x/-/base-x-5.0.0.tgz#6d835ceae379130e1a4cb846a70ac4746f28ea9b" + integrity sha512-sMW3VGSX1QWVFA6l8U62MLKz29rRfpTlYdCqLdpLo1/Yd4zZwSbnUaDfciIAowAqvq7YFnWq9hrhdg1KYgc1lQ== + +base64-js@^1.3.1: version "1.5.1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== @@ -211,6 +722,11 @@ bigint-buffer@^1.1.5: dependencies: bindings "^1.3.0" +bignumber.js@^9.0.1, bignumber.js@^9.1.2: + version "9.1.2" + resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.2.tgz#b7c4242259c008903b13707983b5f4bbd31eda0c" + integrity sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug== + binary-extensions@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" @@ -223,7 +739,7 @@ bindings@^1.3.0: dependencies: file-uri-to-path "1.0.0" -bn.js@^5.0.0, bn.js@^5.1.2, bn.js@^5.2.0: +bn.js@^5.0.0, bn.js@^5.1.2, bn.js@^5.2.0, bn.js@^5.2.1: version "5.2.1" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== @@ -237,13 +753,17 @@ borsh@^0.7.0: bs58 "^4.0.0" text-encoding-utf-8 "^1.0.2" -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== +borsh@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/borsh/-/borsh-2.0.0.tgz#042a9f109565caac3c6a21297cd8c0ae8db3149d" + integrity sha512-kc9+BgR3zz9+cjbwM8ODoUB4fs3X3I5A/HtX7LZKxCLaMrEeDFoBpnhZY//DTS1VZBSs6S5v46RZRbZjRFspEg== + +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== dependencies: balanced-match "^1.0.0" - concat-map "0.0.1" braces@~3.0.2: version "3.0.2" @@ -252,7 +772,7 @@ braces@~3.0.2: dependencies: fill-range "^7.0.1" -browser-stdout@1.3.1: +browser-stdout@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== @@ -264,6 +784,20 @@ bs58@^4.0.0, bs58@^4.0.1: dependencies: base-x "^3.0.2" +bs58@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/bs58/-/bs58-5.0.0.tgz#865575b4d13c09ea2a84622df6c8cbeb54ffc279" + integrity sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ== + dependencies: + base-x "^4.0.0" + +bs58@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/bs58/-/bs58-6.0.0.tgz#a2cda0130558535dd281a2f8697df79caaf425d8" + integrity sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw== + dependencies: + base-x "^5.0.0" + buffer-from@^1.0.0, buffer-from@^1.1.0: version "1.1.2" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" @@ -274,15 +808,7 @@ buffer-layout@^1.2.0, buffer-layout@^1.2.2: resolved "https://registry.yarnpkg.com/buffer-layout/-/buffer-layout-1.2.2.tgz#b9814e7c7235783085f9ca4966a0cfff112259d5" integrity sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA== -buffer@6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.1.tgz#3cbea8c1463e5a0779e30b66d4c88c6ffa182ac2" - integrity sha512-rVAXBwEcEoYtxnHSO5iWyhzV/O1WMtkUYWlfdLS7FjU4PnSJJHEfHXi/uHPI5EwltmOA794gN3bm3/pzuctWjQ== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.2.1" - -buffer@^6.0.1, buffer@~6.0.3: +buffer@6.0.3, buffer@^6.0.3, buffer@~6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== @@ -297,12 +823,7 @@ bufferutil@^4.0.1: dependencies: node-gyp-build "^4.3.0" -camelcase@^5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" - integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== - -camelcase@^6.0.0: +camelcase@^6.0.0, camelcase@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== @@ -328,15 +849,20 @@ chalk@^4.1.0: ansi-styles "^4.1.0" supports-color "^7.1.0" +chalk@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" + integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== + check-error@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" integrity sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA== -chokidar@3.5.3: - version "3.5.3" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" - integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== +chokidar@^3.5.3: + version "3.6.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" + integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== dependencies: anymatch "~3.1.2" braces "~3.0.2" @@ -357,6 +883,15 @@ cliui@^7.0.2: strip-ansi "^6.0.0" wrap-ansi "^7.0.0" +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + color-convert@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" @@ -369,15 +904,20 @@ color-name@~1.1.4: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +commander@^12.0.0, commander@^12.1.0: + version "12.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-12.1.0.tgz#01423b36f501259fdaac4d0e4d60c96c991585d3" + integrity sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA== + commander@^2.20.3: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== +create-require@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" + integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== cross-fetch@^3.1.5: version "3.1.5" @@ -391,10 +931,10 @@ crypto-hash@^1.3.0: resolved "https://registry.yarnpkg.com/crypto-hash/-/crypto-hash-1.3.0.tgz#b402cb08f4529e9f4f09346c3e275942f845e247" integrity sha512-lyAZ0EMyjDkVvz8WOeVnuCPvKVBXcMv1l5SVqO1yC7PzTwrD/pPje/BIRbWhMoPe436U+Y2nD7f5bFx0kt+Sbg== -debug@4.3.3: - version "4.3.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" - integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== +debug@^4.3.5: + version "4.3.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.6.tgz#2ab2c38fbaffebf8aa95fdfe6d88438c7a13c52b" + integrity sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg== dependencies: ms "2.1.2" @@ -403,6 +943,11 @@ decamelize@^4.0.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== +decimal.js@^10.4.3: + version "10.4.3" + resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.3.tgz#1044092884d245d1b7f65725fa4ad4c6f781cc23" + integrity sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA== + deep-eql@^4.1.2: version "4.1.3" resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.1.3.tgz#7c7775513092f7df98d8df9996dd085eb668cc6d" @@ -415,16 +960,21 @@ delay@^5.0.0: resolved "https://registry.yarnpkg.com/delay/-/delay-5.0.0.tgz#137045ef1b96e5071060dd5be60bf9334436bd1d" integrity sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw== -diff@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" - integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== - diff@^3.1.0: version "3.5.0" resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== +diff@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== + +diff@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-5.2.0.tgz#26ded047cd1179b78b9537d5ef725503ce1ae531" + integrity sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A== + dot-case@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751" @@ -433,6 +983,11 @@ dot-case@^3.0.4: no-case "^3.0.4" tslib "^2.0.3" +dotenv@^16.0.3: + version "16.4.5" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f" + integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg== + emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" @@ -455,7 +1010,7 @@ escalade@^3.1.1: resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== -escape-string-regexp@4.0.0: +escape-string-regexp@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== @@ -465,6 +1020,11 @@ eventemitter3@^4.0.7: resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== +eventemitter3@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4" + integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== + eyes@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" @@ -487,7 +1047,7 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" -find-up@5.0.0: +find-up@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== @@ -527,33 +1087,34 @@ glob-parent@~5.1.2: dependencies: is-glob "^4.0.1" -glob@7.2.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" - integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== +glob@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e" + integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" inherits "2" - minimatch "^3.0.4" + minimatch "^5.0.1" once "^1.3.0" - path-is-absolute "^1.0.0" - -growl@1.10.5: - version "1.10.5" - resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" - integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== has-flag@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -he@1.2.0: +he@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== +humanize-ms@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" + integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ== + dependencies: + ms "^2.0.0" + ieee754@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" @@ -611,20 +1172,15 @@ is-unicode-supported@^0.1.0: resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== - isomorphic-ws@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz#55fd4cd6c5e6491e76dc125938dd863f5cd4f2dc" integrity sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w== -jayson@^3.4.4: - version "3.7.0" - resolved "https://registry.yarnpkg.com/jayson/-/jayson-3.7.0.tgz#b735b12d06d348639ae8230d7a1e2916cb078f25" - integrity sha512-tfy39KJMrrXJ+mFcMpxwBvFDetS8LAID93+rycFglIQM4kl3uNR3W4lBLE/FFhsoUCEox5Dt2adVpDm/XtebbQ== +jayson@^4.0.0, jayson@^4.1.0, jayson@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/jayson/-/jayson-4.1.1.tgz#282ff13d3cea09776db684b7eeca98c47b2fa99a" + integrity sha512-5ZWm4Q/0DHPyeMfAsrwViwUS2DMVsQgWh8bEEIVTkfb3DzHZ2L3G5WUnF+AKmGjjM9r1uAv73SaqC1/U4RL45w== dependencies: "@types/connect" "^3.4.33" "@types/node" "^12.12.54" @@ -636,16 +1192,24 @@ jayson@^3.4.4: eyes "^0.1.8" isomorphic-ws "^4.0.1" json-stringify-safe "^5.0.1" - lodash "^4.17.20" uuid "^8.3.2" - ws "^7.4.5" - -js-sha256@^0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/js-sha256/-/js-sha256-0.9.0.tgz#0b89ac166583e91ef9123644bd3c5334ce9d0966" - integrity sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA== + ws "^7.5.10" -js-yaml@4.1.0: +jito-ts@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/jito-ts/-/jito-ts-3.0.1.tgz#24126389896e042c26d303c4e802064b249ed27e" + integrity sha512-TSofF7KqcwyaWGjPaSYC8RDoNBY1TPRNBHdrw24bdIi7mQ5bFEDdYK3D//llw/ml8YDvcZlgd644WxhjLTS9yg== + dependencies: + "@grpc/grpc-js" "^1.8.13" + "@noble/ed25519" "^1.7.1" + "@solana/web3.js" "~1.77.3" + agentkeepalive "^4.3.0" + dotenv "^16.0.3" + jayson "^4.0.0" + node-fetch "^2.6.7" + superstruct "^1.0.3" + +js-yaml@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== @@ -676,12 +1240,12 @@ locate-path@^6.0.0: dependencies: p-locate "^5.0.0" -lodash@^4.17.20: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== +lodash.camelcase@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" + integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== -log-symbols@4.1.0: +log-symbols@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== @@ -689,6 +1253,11 @@ log-symbols@4.1.0: chalk "^4.1.0" is-unicode-supported "^0.1.0" +long@^5.0.0: + version "5.2.3" + resolved "https://registry.yarnpkg.com/long/-/long-5.2.3.tgz#a3ba97f3877cf1d778eccbcb048525ebb77499e1" + integrity sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q== + loupe@^2.3.1: version "2.3.6" resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.6.tgz#76e4af498103c532d1ecc9be102036a21f787b53" @@ -708,19 +1277,12 @@ make-error@^1.1.1: resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== -minimatch@4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-4.2.1.tgz#40d9d511a46bdc4e563c22c3080cde9c0d8299b4" - integrity sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g== - dependencies: - brace-expansion "^1.1.7" - -minimatch@^3.0.4: - version "3.1.2" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== +minimatch@^5.0.1, minimatch@^5.1.6: + version "5.1.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== dependencies: - brace-expansion "^1.1.7" + brace-expansion "^2.0.1" minimist@^1.2.0, minimist@^1.2.6: version "1.2.7" @@ -734,51 +1296,42 @@ mkdirp@^0.5.1: dependencies: minimist "^1.2.6" -mocha@^9.0.3: - version "9.2.2" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-9.2.2.tgz#d70db46bdb93ca57402c809333e5a84977a88fb9" - integrity sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g== - dependencies: - "@ungap/promise-all-settled" "1.1.2" - ansi-colors "4.1.1" - browser-stdout "1.3.1" - chokidar "3.5.3" - debug "4.3.3" - diff "5.0.0" - escape-string-regexp "4.0.0" - find-up "5.0.0" - glob "7.2.0" - growl "1.10.5" - he "1.2.0" - js-yaml "4.1.0" - log-symbols "4.1.0" - minimatch "4.2.1" - ms "2.1.3" - nanoid "3.3.1" - serialize-javascript "6.0.0" - strip-json-comments "3.1.1" - supports-color "8.1.1" - which "2.0.2" - workerpool "6.2.0" - yargs "16.2.0" - yargs-parser "20.2.4" - yargs-unparser "2.0.0" +mocha@^10.2.0: + version "10.7.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.7.0.tgz#9e5cbed8fa9b37537a25bd1f7fb4f6fc45458b9a" + integrity sha512-v8/rBWr2VO5YkspYINnvu81inSz2y3ODJrhO175/Exzor1RcEZZkizgE2A+w/CAXXoESS8Kys5E62dOHGHzULA== + dependencies: + ansi-colors "^4.1.3" + browser-stdout "^1.3.1" + chokidar "^3.5.3" + debug "^4.3.5" + diff "^5.2.0" + escape-string-regexp "^4.0.0" + find-up "^5.0.0" + glob "^8.1.0" + he "^1.2.0" + js-yaml "^4.1.0" + log-symbols "^4.1.0" + minimatch "^5.1.6" + ms "^2.1.3" + serialize-javascript "^6.0.2" + strip-json-comments "^3.1.1" + supports-color "^8.1.1" + workerpool "^6.5.1" + yargs "^16.2.0" + yargs-parser "^20.2.9" + yargs-unparser "^2.0.0" ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3: +ms@^2.0.0, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -nanoid@3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35" - integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw== - no-case@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d" @@ -787,13 +1340,20 @@ no-case@^3.0.4: lower-case "^2.0.2" tslib "^2.0.3" -node-fetch@2, node-fetch@2.6.7: +node-fetch@2.6.7: version "2.6.7" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== dependencies: whatwg-url "^5.0.0" +node-fetch@^2.6.7, node-fetch@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== + dependencies: + whatwg-url "^5.0.0" + node-gyp-build@^4.3.0: version "4.5.0" resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.5.0.tgz#7a64eefa0b21112f89f58379da128ac177f20e40" @@ -804,6 +1364,11 @@ normalize-path@^3.0.0, normalize-path@~3.0.0: resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== +numeral@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/numeral/-/numeral-2.0.6.tgz#4ad080936d443c2561aed9f2197efffe25f4e506" + integrity sha512-qaKRmtYPZ5qdw4jWJD6bxEf1FJEqllJrwxCLIm0sQU/A7v2/czigzOb+C2uSiFsa9lBUzeH7M1oK+Q+OLxL3kA== + once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -835,11 +1400,6 @@ path-exists@^4.0.0: resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== - pathval@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" @@ -855,6 +1415,24 @@ prettier@^2.6.2: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.1.tgz#4e1fd11c34e2421bc1da9aea9bd8127cd0a35efc" integrity sha512-lqGoSJBQNJidqCHE80vqZJHWHRFoNYsSpP9AjFhlhi9ODCJA541svILes/+/1GM3VaL/abZi7cpFzOpdR9UPKg== +protobufjs@^7.2.5: + version "7.3.2" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.3.2.tgz#60f3b7624968868f6f739430cfbc8c9370e26df4" + integrity sha512-RXyHaACeqXeqAKGLDl68rQKbmObRsTIn4TYVUUug1KfS47YWCo5MacGITEryugIgZqORCvJWEk4l449POg5Txg== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/node" ">=13.7.0" + long "^5.0.0" + randombytes@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" @@ -869,22 +1447,21 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" -regenerator-runtime@^0.13.11: - version "0.13.11" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" - integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== +regenerator-runtime@^0.14.0: + version "0.14.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" + integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== -rpc-websockets@^7.5.0: - version "7.5.0" - resolved "https://registry.yarnpkg.com/rpc-websockets/-/rpc-websockets-7.5.0.tgz#bbeb87572e66703ff151e50af1658f98098e2748" - integrity sha512-9tIRi1uZGy7YmDjErf1Ax3wtqdSSLIlnmL5OtOzgd5eqPKbsPpwDP5whUDO2LQay3Xp0CcHlcNSGzacNRluBaQ== +rpc-websockets@^7.5.1: + version "7.11.2" + resolved "https://registry.yarnpkg.com/rpc-websockets/-/rpc-websockets-7.11.2.tgz#582910c425b9f2c860327481c1d1e0e431bf4a6d" + integrity sha512-pL9r5N6AVHlMN/vT98+fcO+5+/UcPLf/4tq+WUaid/PPUGS/ttJ3y8e9IqmaWKtShNAysMSjkczuEA49NuV7UQ== dependencies: - "@babel/runtime" "^7.17.2" eventemitter3 "^4.0.7" uuid "^8.3.2" ws "^8.5.0" @@ -892,15 +1469,31 @@ rpc-websockets@^7.5.0: bufferutil "^4.0.1" utf-8-validate "^5.0.2" +rpc-websockets@^9.0.2: + version "9.0.2" + resolved "https://registry.yarnpkg.com/rpc-websockets/-/rpc-websockets-9.0.2.tgz#4c1568d00b8100f997379a363478f41f8f4b242c" + integrity sha512-YzggvfItxMY3Lwuax5rC18inhbjJv9Py7JXRHxTIi94JOLrqBsSsUUc5bbl5W6c11tXhdfpDPK0KzBhoGe8jjw== + dependencies: + "@swc/helpers" "^0.5.11" + "@types/uuid" "^8.3.4" + "@types/ws" "^8.2.2" + buffer "^6.0.3" + eventemitter3 "^5.0.1" + uuid "^8.3.2" + ws "^8.5.0" + optionalDependencies: + bufferutil "^4.0.1" + utf-8-validate "^5.0.2" + safe-buffer@^5.0.1, safe-buffer@^5.1.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== -serialize-javascript@6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" - integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== +serialize-javascript@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2" + integrity sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g== dependencies: randombytes "^2.1.0" @@ -925,7 +1518,7 @@ source-map@^0.6.0: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== -string-width@^4.1.0, string-width@^4.2.0: +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -946,7 +1539,7 @@ strip-bom@^3.0.0: resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== -strip-json-comments@3.1.1: +strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== @@ -961,12 +1554,15 @@ superstruct@^0.15.4: resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-0.15.5.tgz#0f0a8d3ce31313f0d84c6096cd4fa1bfdedc9dab" integrity sha512-4AOeU+P5UuE/4nOUkmcQdW5y7i9ndt1cQd/3iUe+LTz3RxESf/W/5lg4B74HbDMMv8PHnPnGCQFH45kBcrQYoQ== -supports-color@8.1.1: - version "8.1.1" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" - integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== - dependencies: - has-flag "^4.0.0" +superstruct@^1.0.3, superstruct@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-1.0.4.tgz#0adb99a7578bd2f1c526220da6571b2d485d91ca" + integrity sha512-7JpaAoX2NGyoFlI9NBh66BQXGONc+uE+MRS5i2iOBKuS4e+ccgMDjATgZldkah+33DakBxDHiss9kvUcGAO8UQ== + +superstruct@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-2.0.2.tgz#3f6d32fbdc11c357deff127d591a39b996300c54" + integrity sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A== supports-color@^7.1.0: version "7.2.0" @@ -975,6 +1571,13 @@ supports-color@^7.1.0: dependencies: has-flag "^4.0.0" +supports-color@^8.1.1: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + text-encoding-utf-8@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz#585b62197b0ae437e3c7b5d0af27ac1021e10d13" @@ -1025,6 +1628,25 @@ ts-node@7.0.1: source-map-support "^0.5.6" yn "^2.0.0" +ts-node@^10.9.1: + version "10.9.2" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" + integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== + dependencies: + "@cspotcode/source-map-support" "^0.8.0" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" + arg "^4.1.0" + create-require "^1.1.0" + diff "^4.0.1" + make-error "^1.1.1" + v8-compile-cache-lib "^3.0.1" + yn "3.1.1" + tsconfig-paths@^3.5.0: version "3.14.1" resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a" @@ -1040,6 +1662,11 @@ tslib@^2.0.3: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e" integrity sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA== +tslib@^2.4.0: + version "2.6.3" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.3.tgz#0438f810ad7a9edcde7a241c3d80db693c8cbfe0" + integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ== + type-detect@^4.0.0, type-detect@^4.0.5: version "4.0.8" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" @@ -1050,6 +1677,11 @@ typescript@^4.3.5: resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.4.tgz#a2a3d2756c079abda241d75f149df9d561091e78" integrity sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg== +undici-types@~6.18.2: + version "6.18.2" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.18.2.tgz#8b678cf939d4fc9ec56be3c68ed69c619dee28b0" + integrity sha512-5ruQbENj95yDYJNS3TvcaxPMshV7aizdv/hWYjGIKoANWKjhWNBsr2YEuYZKodQulB1b8l7ILOuDQep3afowQQ== + utf-8-validate@^5.0.2: version "5.0.10" resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-5.0.10.tgz#d7d10ea39318171ca982718b6b96a8d2442571a2" @@ -1062,6 +1694,11 @@ uuid@^8.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== +v8-compile-cache-lib@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" + integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== + webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" @@ -1075,17 +1712,10 @@ whatwg-url@^5.0.0: tr46 "~0.0.3" webidl-conversions "^3.0.0" -which@2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -workerpool@6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.0.tgz#827d93c9ba23ee2019c3ffaff5c27fccea289e8b" - integrity sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A== +workerpool@^6.5.1: + version "6.5.1" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.5.1.tgz#060f73b39d0caf97c6db64da004cd01b4c099544" + integrity sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA== wrap-ansi@^7.0.0: version "7.0.0" @@ -1101,10 +1731,10 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== -ws@^7.4.5: - version "7.5.9" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" - integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== +ws@^7.5.10: + version "7.5.10" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9" + integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== ws@^8.5.0: version "8.11.0" @@ -1116,17 +1746,17 @@ y18n@^5.0.5: resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== -yargs-parser@20.2.4: - version "20.2.4" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" - integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== - -yargs-parser@^20.2.2: +yargs-parser@^20.2.2, yargs-parser@^20.2.9: version "20.2.9" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== -yargs-unparser@2.0.0: +yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + +yargs-unparser@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== @@ -1136,7 +1766,7 @@ yargs-unparser@2.0.0: flat "^5.0.2" is-plain-obj "^2.1.0" -yargs@16.2.0: +yargs@^16.2.0: version "16.2.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== @@ -1149,6 +1779,24 @@ yargs@16.2.0: y18n "^5.0.5" yargs-parser "^20.2.2" +yargs@^17.7.2: + version "17.7.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1" + +yn@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== + yn@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/yn/-/yn-2.0.0.tgz#e5adabc8acf408f6385fc76495684c88e6af689a"