From 50f67c12fc83dd354c72a59d9773fe0eec9b25d9 Mon Sep 17 00:00:00 2001 From: Alex Janiak Date: Tue, 17 Feb 2026 10:26:49 -0500 Subject: [PATCH 01/19] feat: scaffold redemption program - Add new redemption program structure following vault pattern - Program ID: rdm5xmgfjVn2WXCNrdEuBDoj3JJHt7K6M82jBnXf1Ef - Add to Anchor.toml (devnet, localnet, mainnet) - Create lib.rs, state.rs, errors.rs, constants.rs, instructions/mod.rs - Store keypair in .keys/redemption.json --- Anchor.toml | 3 ++ Cargo.lock | 8 +++++ programs/redemption/Cargo.toml | 29 ++++++++++++++++++ programs/redemption/src/constants.rs | 24 +++++++++++++++ programs/redemption/src/errors.rs | 25 +++++++++++++++ programs/redemption/src/instructions/mod.rs | 20 ++++++++++++ programs/redemption/src/lib.rs | 34 +++++++++++++++++++++ programs/redemption/src/state.rs | 19 ++++++++++++ 8 files changed, 162 insertions(+) create mode 100644 programs/redemption/Cargo.toml create mode 100644 programs/redemption/src/constants.rs create mode 100644 programs/redemption/src/errors.rs create mode 100644 programs/redemption/src/instructions/mod.rs create mode 100644 programs/redemption/src/lib.rs create mode 100644 programs/redemption/src/state.rs diff --git a/Anchor.toml b/Anchor.toml index ffb78b9..4ae0754 100644 --- a/Anchor.toml +++ b/Anchor.toml @@ -8,18 +8,21 @@ skip-lint = false [programs.devnet] amm = "AMMSgtnttAKx5Ad2Y1socKJ3CcQYCB2ctg8U2SAHcVEx" futarchy = "FUTKPrt66uGGCTpk6f9tmRX2325cWgXzGCwvWhyyzjea" +redemption = "rdm5xmgfjVn2WXCNrdEuBDoj3JJHt7K6M82jBnXf1Ef" svault = "GmH3zEvgmWoC6Y6hxinYYRWLCuxUikRN5SAmVDVF4Jjy" vault = "VLTEetGyPKtffi1u3Jr8btWATv33NeDyUuRsPENFPTU" [programs.localnet] amm = "AMMSgtnttAKx5Ad2Y1socKJ3CcQYCB2ctg8U2SAHcVEx" futarchy = "FUTKPrt66uGGCTpk6f9tmRX2325cWgXzGCwvWhyyzjea" +redemption = "rdm5xmgfjVn2WXCNrdEuBDoj3JJHt7K6M82jBnXf1Ef" svault = "GmH3zEvgmWoC6Y6hxinYYRWLCuxUikRN5SAmVDVF4Jjy" vault = "VLTEetGyPKtffi1u3Jr8btWATv33NeDyUuRsPENFPTU" [programs.mainnet] amm = "AMMSgtnttAKx5Ad2Y1socKJ3CcQYCB2ctg8U2SAHcVEx" futarchy = "FUTKPrt66uGGCTpk6f9tmRX2325cWgXzGCwvWhyyzjea" +redemption = "rdm5xmgfjVn2WXCNrdEuBDoj3JJHt7K6M82jBnXf1Ef" svault = "GmH3zEvgmWoC6Y6hxinYYRWLCuxUikRN5SAmVDVF4Jjy" vault = "VLTEetGyPKtffi1u3Jr8btWATv33NeDyUuRsPENFPTU" diff --git a/Cargo.lock b/Cargo.lock index 4db15b1..63c1307 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1207,6 +1207,14 @@ dependencies = [ "rand_core 0.5.1", ] +[[package]] +name = "redemption" +version = "0.1.0" +dependencies = [ + "anchor-lang", + "anchor-spl", +] + [[package]] name = "redox_syscall" version = "0.5.18" diff --git a/programs/redemption/Cargo.toml b/programs/redemption/Cargo.toml new file mode 100644 index 0000000..bc6ea87 --- /dev/null +++ b/programs/redemption/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "redemption" +version = "0.1.0" +description = "Created with Anchor" +edition = "2021" + +[lib] +crate-type = ["cdylib", "lib"] +name = "redemption" + +[features] +default = [] +cpi = ["no-entrypoint"] +no-entrypoint = [] +no-idl = [] +no-log-ix-name = [] +idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"] +anchor-debug = [] +custom-heap = [] +custom-panic = [] + + +[dependencies] +anchor-lang = { version = "0.32.1", features = ["init-if-needed"] } +anchor-spl = "0.32.1" + + +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = ['cfg(target_os, values("solana"))'] } diff --git a/programs/redemption/src/constants.rs b/programs/redemption/src/constants.rs new file mode 100644 index 0000000..8bd0286 --- /dev/null +++ b/programs/redemption/src/constants.rs @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2025 Spice Finance Inc. + * + * This file is part of Z Combinator. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +use anchor_lang::prelude::*; + +#[constant] +pub const REDEMPTION_VERSION: u8 = 1; + +// TODO: Add constants diff --git a/programs/redemption/src/errors.rs b/programs/redemption/src/errors.rs new file mode 100644 index 0000000..b5c9243 --- /dev/null +++ b/programs/redemption/src/errors.rs @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2025 Spice Finance Inc. + * + * This file is part of Z Combinator. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +use anchor_lang::prelude::*; + +#[error_code] +pub enum RedemptionError { + #[msg("Placeholder error")] + Placeholder, +} diff --git a/programs/redemption/src/instructions/mod.rs b/programs/redemption/src/instructions/mod.rs new file mode 100644 index 0000000..f6dbcae --- /dev/null +++ b/programs/redemption/src/instructions/mod.rs @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2025 Spice Finance Inc. + * + * This file is part of Z Combinator. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +// TODO: Add instruction modules diff --git a/programs/redemption/src/lib.rs b/programs/redemption/src/lib.rs new file mode 100644 index 0000000..0e100c2 --- /dev/null +++ b/programs/redemption/src/lib.rs @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2025 Spice Finance Inc. + * + * This file is part of Z Combinator. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +use anchor_lang::prelude::*; + +declare_id!("rdm5xmgfjVn2WXCNrdEuBDoj3JJHt7K6M82jBnXf1Ef"); + +pub mod constants; +pub mod errors; +pub mod instructions; +pub mod state; + +pub use constants::*; +pub use errors::*; + +#[program] +pub mod redemption { + // TODO: Add instructions +} diff --git a/programs/redemption/src/state.rs b/programs/redemption/src/state.rs new file mode 100644 index 0000000..741394c --- /dev/null +++ b/programs/redemption/src/state.rs @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2025 Spice Finance Inc. + * + * This file is part of Z Combinator. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +// TODO: Add state accounts From aa5fcbf8081a245467be7358c2e99d0e54a2840e Mon Sep 17 00:00:00 2001 From: Alex Janiak Date: Tue, 17 Feb 2026 10:29:35 -0500 Subject: [PATCH 02/19] feat(redemption): implement treasury redemption contract Implements a secure token redemption system for liquidating treasury: ## Instructions - initialize: Admin sets price and deposits quote tokens - deposit: Admin adds more quote tokens - withdraw: Admin reclaims quote and/or collected base tokens - redeem: Users exchange base tokens for quote at set price ## Security - Overflow protection using u128 intermediate calculations - InsufficientVaultBalance check before any transfers - Zero-amount validation on all operations - QuoteAmountTooSmall prevents dust redemptions - Admin-only access control on deposit/withdraw - PDA-signed transfers for vault operations ## State - RedemptionVault: stores admin, mints, price, decimals, stats - Events emitted for all operations for indexing --- programs/redemption/src/constants.rs | 3 +- programs/redemption/src/errors.rs | 22 +- .../redemption/src/instructions/deposit.rs | 90 ++++++++ .../redemption/src/instructions/initialize.rs | 129 ++++++++++++ programs/redemption/src/instructions/mod.rs | 10 +- .../redemption/src/instructions/redeem.rs | 193 ++++++++++++++++++ .../redemption/src/instructions/withdraw.rs | 165 +++++++++++++++ programs/redemption/src/lib.rs | 43 +++- programs/redemption/src/state.rs | 27 ++- 9 files changed, 676 insertions(+), 6 deletions(-) create mode 100644 programs/redemption/src/instructions/deposit.rs create mode 100644 programs/redemption/src/instructions/initialize.rs create mode 100644 programs/redemption/src/instructions/redeem.rs create mode 100644 programs/redemption/src/instructions/withdraw.rs diff --git a/programs/redemption/src/constants.rs b/programs/redemption/src/constants.rs index 8bd0286..d9c522b 100644 --- a/programs/redemption/src/constants.rs +++ b/programs/redemption/src/constants.rs @@ -21,4 +21,5 @@ use anchor_lang::prelude::*; #[constant] pub const REDEMPTION_VERSION: u8 = 1; -// TODO: Add constants +#[constant] +pub const VAULT_SEED: &[u8] = b"redemption_vault"; diff --git a/programs/redemption/src/errors.rs b/programs/redemption/src/errors.rs index b5c9243..6b6fc66 100644 --- a/programs/redemption/src/errors.rs +++ b/programs/redemption/src/errors.rs @@ -20,6 +20,24 @@ use anchor_lang::prelude::*; #[error_code] pub enum RedemptionError { - #[msg("Placeholder error")] - Placeholder, + #[msg("Unauthorized: only admin can perform this action")] + Unauthorized, + + #[msg("Invalid amount: must be greater than zero")] + InvalidAmount, + + #[msg("Invalid price: must be greater than zero")] + InvalidPrice, + + #[msg("Insufficient vault balance: not enough quote tokens to fulfill redemption")] + InsufficientVaultBalance, + + #[msg("Arithmetic overflow occurred")] + Overflow, + + #[msg("Arithmetic underflow occurred")] + Underflow, + + #[msg("Quote amount too small: redemption would yield zero tokens")] + QuoteAmountTooSmall, } diff --git a/programs/redemption/src/instructions/deposit.rs b/programs/redemption/src/instructions/deposit.rs new file mode 100644 index 0000000..818bedd --- /dev/null +++ b/programs/redemption/src/instructions/deposit.rs @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2025 Spice Finance Inc. + * + * This file is part of Z Combinator. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +use anchor_lang::prelude::*; +use anchor_spl::associated_token::AssociatedToken; +use anchor_spl::token::{self, Mint, Token, TokenAccount, Transfer}; + +use crate::constants::*; +use crate::errors::RedemptionError; +use crate::state::RedemptionVault; + +#[event] +pub struct QuoteDeposited { + pub vault: Pubkey, + pub admin: Pubkey, + pub amount: u64, +} + +#[derive(Accounts)] +pub struct Deposit<'info> { + /// Admin depositing more quote tokens + #[account(mut)] + pub admin: Signer<'info>, + + /// The redemption vault + #[account( + mut, + seeds = [VAULT_SEED, vault.base_mint.as_ref(), vault.quote_mint.as_ref()], + bump = vault.bump, + constraint = vault.admin == admin.key() @ RedemptionError::Unauthorized, + )] + pub vault: Account<'info, RedemptionVault>, + + pub quote_mint: Account<'info, Mint>, + + /// Vault's quote token account + #[account( + mut, + associated_token::mint = quote_mint, + associated_token::authority = vault, + )] + pub vault_quote_ata: Account<'info, TokenAccount>, + + /// Admin's quote token account + #[account( + mut, + associated_token::mint = quote_mint, + associated_token::authority = admin, + )] + pub admin_quote_ata: Account<'info, TokenAccount>, + + pub token_program: Program<'info, Token>, + pub associated_token_program: Program<'info, AssociatedToken>, +} + +pub fn deposit_handler(ctx: Context, amount: u64) -> Result<()> { + require!(amount > 0, RedemptionError::InvalidAmount); + + // Transfer quote tokens from admin to vault + let cpi_accounts = Transfer { + from: ctx.accounts.admin_quote_ata.to_account_info(), + to: ctx.accounts.vault_quote_ata.to_account_info(), + authority: ctx.accounts.admin.to_account_info(), + }; + let cpi_ctx = CpiContext::new(ctx.accounts.token_program.to_account_info(), cpi_accounts); + token::transfer(cpi_ctx, amount)?; + + emit!(QuoteDeposited { + vault: ctx.accounts.vault.key(), + admin: ctx.accounts.admin.key(), + amount, + }); + + Ok(()) +} diff --git a/programs/redemption/src/instructions/initialize.rs b/programs/redemption/src/instructions/initialize.rs new file mode 100644 index 0000000..882f2b1 --- /dev/null +++ b/programs/redemption/src/instructions/initialize.rs @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2025 Spice Finance Inc. + * + * This file is part of Z Combinator. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +use anchor_lang::prelude::*; +use anchor_spl::associated_token::AssociatedToken; +use anchor_spl::token::{self, Mint, Token, TokenAccount, Transfer}; + +use crate::constants::*; +use crate::errors::RedemptionError; +use crate::state::RedemptionVault; + +#[event] +pub struct VaultInitialized { + pub vault: Pubkey, + pub admin: Pubkey, + pub base_mint: Pubkey, + pub quote_mint: Pubkey, + pub price: u64, + pub initial_deposit: u64, +} + +#[derive(Accounts)] +pub struct Initialize<'info> { + /// Admin who will control the vault + #[account(mut)] + pub admin: Signer<'info>, + + /// The redemption vault PDA + #[account( + init, + payer = admin, + space = 8 + RedemptionVault::INIT_SPACE, + seeds = [VAULT_SEED, base_mint.key().as_ref(), quote_mint.key().as_ref()], + bump, + )] + pub vault: Account<'info, RedemptionVault>, + + /// The token users will send (base mint) + pub base_mint: Account<'info, Mint>, + + /// The token users will receive (quote mint) + pub quote_mint: Account<'info, Mint>, + + /// Vault's ATA for holding quote tokens + #[account( + init, + payer = admin, + associated_token::mint = quote_mint, + associated_token::authority = vault, + )] + pub vault_quote_ata: Account<'info, TokenAccount>, + + /// Vault's ATA for receiving base tokens (burn destination) + #[account( + init, + payer = admin, + associated_token::mint = base_mint, + associated_token::authority = vault, + )] + pub vault_base_ata: Account<'info, TokenAccount>, + + /// Admin's quote token account (source of initial deposit) + #[account( + mut, + associated_token::mint = quote_mint, + associated_token::authority = admin, + )] + pub admin_quote_ata: Account<'info, TokenAccount>, + + pub system_program: Program<'info, System>, + pub token_program: Program<'info, Token>, + pub associated_token_program: Program<'info, AssociatedToken>, +} + +pub fn initialize_handler( + ctx: Context, + price: u64, + initial_deposit: u64, +) -> Result<()> { + require!(price > 0, RedemptionError::InvalidPrice); + require!(initial_deposit > 0, RedemptionError::InvalidAmount); + + let vault = &mut ctx.accounts.vault; + + vault.version = REDEMPTION_VERSION; + vault.bump = ctx.bumps.vault; + vault.admin = ctx.accounts.admin.key(); + vault.base_mint = ctx.accounts.base_mint.key(); + vault.quote_mint = ctx.accounts.quote_mint.key(); + vault.price = price; + vault.base_decimals = ctx.accounts.base_mint.decimals; + vault.quote_decimals = ctx.accounts.quote_mint.decimals; + vault.total_redeemed = 0; + + // Transfer initial quote tokens from admin to vault + let cpi_accounts = Transfer { + from: ctx.accounts.admin_quote_ata.to_account_info(), + to: ctx.accounts.vault_quote_ata.to_account_info(), + authority: ctx.accounts.admin.to_account_info(), + }; + let cpi_ctx = CpiContext::new(ctx.accounts.token_program.to_account_info(), cpi_accounts); + token::transfer(cpi_ctx, initial_deposit)?; + + emit!(VaultInitialized { + vault: vault.key(), + admin: vault.admin, + base_mint: vault.base_mint, + quote_mint: vault.quote_mint, + price, + initial_deposit, + }); + + Ok(()) +} diff --git a/programs/redemption/src/instructions/mod.rs b/programs/redemption/src/instructions/mod.rs index f6dbcae..58a3ec8 100644 --- a/programs/redemption/src/instructions/mod.rs +++ b/programs/redemption/src/instructions/mod.rs @@ -17,4 +17,12 @@ * along with this program. If not, see . */ -// TODO: Add instruction modules +pub mod deposit; +pub mod initialize; +pub mod redeem; +pub mod withdraw; + +pub use deposit::*; +pub use initialize::*; +pub use redeem::*; +pub use withdraw::*; diff --git a/programs/redemption/src/instructions/redeem.rs b/programs/redemption/src/instructions/redeem.rs new file mode 100644 index 0000000..a3baa48 --- /dev/null +++ b/programs/redemption/src/instructions/redeem.rs @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2025 Spice Finance Inc. + * + * This file is part of Z Combinator. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +use anchor_lang::prelude::*; +use anchor_spl::associated_token::AssociatedToken; +use anchor_spl::token::{self, Mint, Token, TokenAccount, Transfer}; + +use crate::constants::*; +use crate::errors::RedemptionError; +use crate::state::RedemptionVault; + +#[event] +pub struct TokensRedeemed { + pub vault: Pubkey, + pub user: Pubkey, + pub base_amount: u64, + pub quote_amount: u64, +} + +#[derive(Accounts)] +pub struct Redeem<'info> { + /// User redeeming tokens + #[account(mut)] + pub user: Signer<'info>, + + /// The redemption vault + #[account( + mut, + seeds = [VAULT_SEED, vault.base_mint.as_ref(), vault.quote_mint.as_ref()], + bump = vault.bump, + )] + pub vault: Account<'info, RedemptionVault>, + + pub base_mint: Account<'info, Mint>, + pub quote_mint: Account<'info, Mint>, + + /// Vault's quote token account (source) + #[account( + mut, + associated_token::mint = quote_mint, + associated_token::authority = vault, + )] + pub vault_quote_ata: Account<'info, TokenAccount>, + + /// Vault's base token account (receives user's base tokens) + #[account( + mut, + associated_token::mint = base_mint, + associated_token::authority = vault, + )] + pub vault_base_ata: Account<'info, TokenAccount>, + + /// User's base token account (source - tokens being redeemed) + #[account( + mut, + associated_token::mint = base_mint, + associated_token::authority = user, + )] + pub user_base_ata: Account<'info, TokenAccount>, + + /// User's quote token account (destination - tokens being received) + #[account( + init_if_needed, + payer = user, + associated_token::mint = quote_mint, + associated_token::authority = user, + )] + pub user_quote_ata: Account<'info, TokenAccount>, + + pub system_program: Program<'info, System>, + pub token_program: Program<'info, Token>, + pub associated_token_program: Program<'info, AssociatedToken>, +} + +/// Calculate quote amount from base amount +/// Formula: quote_amount = (base_amount * price) / 10^base_decimals +/// This normalizes for different decimal places between tokens +fn calculate_quote_amount( + base_amount: u64, + price: u64, + base_decimals: u8, +) -> Result { + // Use u128 for intermediate calculation to prevent overflow + let base_amount_u128 = base_amount as u128; + let price_u128 = price as u128; + let divisor = 10u128.pow(base_decimals as u32); + + let quote_amount_u128 = base_amount_u128 + .checked_mul(price_u128) + .ok_or(RedemptionError::Overflow)? + .checked_div(divisor) + .ok_or(RedemptionError::Overflow)?; + + // Ensure result fits in u64 + if quote_amount_u128 > u64::MAX as u128 { + return Err(RedemptionError::Overflow.into()); + } + + Ok(quote_amount_u128 as u64) +} + +pub fn redeem_handler(ctx: Context, base_amount: u64) -> Result<()> { + require!(base_amount > 0, RedemptionError::InvalidAmount); + + let vault = &ctx.accounts.vault; + + // Calculate how much quote the user should receive + let quote_amount = calculate_quote_amount( + base_amount, + vault.price, + vault.base_decimals, + )?; + + // Ensure the redemption yields a non-zero amount + require!(quote_amount > 0, RedemptionError::QuoteAmountTooSmall); + + // Check vault has sufficient quote tokens BEFORE any transfers + require!( + ctx.accounts.vault_quote_ata.amount >= quote_amount, + RedemptionError::InsufficientVaultBalance + ); + + // Check user has sufficient base tokens + require!( + ctx.accounts.user_base_ata.amount >= base_amount, + RedemptionError::InvalidAmount + ); + + // Transfer base tokens from user to vault + let cpi_accounts = Transfer { + from: ctx.accounts.user_base_ata.to_account_info(), + to: ctx.accounts.vault_base_ata.to_account_info(), + authority: ctx.accounts.user.to_account_info(), + }; + let cpi_ctx = CpiContext::new(ctx.accounts.token_program.to_account_info(), cpi_accounts); + token::transfer(cpi_ctx, base_amount)?; + + // Transfer quote tokens from vault to user (PDA signed) + let base_mint_key = vault.base_mint; + let quote_mint_key = vault.quote_mint; + let bump = vault.bump; + + let seeds = &[ + VAULT_SEED, + base_mint_key.as_ref(), + quote_mint_key.as_ref(), + &[bump], + ]; + let signer_seeds = &[&seeds[..]]; + + let cpi_accounts = Transfer { + from: ctx.accounts.vault_quote_ata.to_account_info(), + to: ctx.accounts.user_quote_ata.to_account_info(), + authority: ctx.accounts.vault.to_account_info(), + }; + let cpi_ctx = CpiContext::new_with_signer( + ctx.accounts.token_program.to_account_info(), + cpi_accounts, + signer_seeds, + ); + token::transfer(cpi_ctx, quote_amount)?; + + // Update stats + let vault = &mut ctx.accounts.vault; + vault.total_redeemed = vault + .total_redeemed + .checked_add(base_amount) + .ok_or(RedemptionError::Overflow)?; + + emit!(TokensRedeemed { + vault: ctx.accounts.vault.key(), + user: ctx.accounts.user.key(), + base_amount, + quote_amount, + }); + + Ok(()) +} diff --git a/programs/redemption/src/instructions/withdraw.rs b/programs/redemption/src/instructions/withdraw.rs new file mode 100644 index 0000000..00a65a6 --- /dev/null +++ b/programs/redemption/src/instructions/withdraw.rs @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2025 Spice Finance Inc. + * + * This file is part of Z Combinator. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +use anchor_lang::prelude::*; +use anchor_spl::associated_token::AssociatedToken; +use anchor_spl::token::{self, Mint, Token, TokenAccount, Transfer}; + +use crate::constants::*; +use crate::errors::RedemptionError; +use crate::state::RedemptionVault; + +#[event] +pub struct AdminWithdrawal { + pub vault: Pubkey, + pub admin: Pubkey, + pub quote_amount: u64, + pub base_amount: u64, +} + +#[derive(Accounts)] +pub struct Withdraw<'info> { + /// Admin withdrawing funds + #[account(mut)] + pub admin: Signer<'info>, + + /// The redemption vault + #[account( + mut, + seeds = [VAULT_SEED, vault.base_mint.as_ref(), vault.quote_mint.as_ref()], + bump = vault.bump, + constraint = vault.admin == admin.key() @ RedemptionError::Unauthorized, + )] + pub vault: Account<'info, RedemptionVault>, + + pub base_mint: Account<'info, Mint>, + pub quote_mint: Account<'info, Mint>, + + /// Vault's quote token account + #[account( + mut, + associated_token::mint = quote_mint, + associated_token::authority = vault, + )] + pub vault_quote_ata: Account<'info, TokenAccount>, + + /// Vault's base token account (collected from redemptions) + #[account( + mut, + associated_token::mint = base_mint, + associated_token::authority = vault, + )] + pub vault_base_ata: Account<'info, TokenAccount>, + + /// Admin's quote token account + #[account( + init_if_needed, + payer = admin, + associated_token::mint = quote_mint, + associated_token::authority = admin, + )] + pub admin_quote_ata: Account<'info, TokenAccount>, + + /// Admin's base token account + #[account( + init_if_needed, + payer = admin, + associated_token::mint = base_mint, + associated_token::authority = admin, + )] + pub admin_base_ata: Account<'info, TokenAccount>, + + pub system_program: Program<'info, System>, + pub token_program: Program<'info, Token>, + pub associated_token_program: Program<'info, AssociatedToken>, +} + +pub fn withdraw_handler( + ctx: Context, + quote_amount: Option, + base_amount: Option, +) -> Result<()> { + let vault = &ctx.accounts.vault; + let base_mint_key = vault.base_mint; + let quote_mint_key = vault.quote_mint; + let bump = vault.bump; + + let seeds = &[ + VAULT_SEED, + base_mint_key.as_ref(), + quote_mint_key.as_ref(), + &[bump], + ]; + let signer_seeds = &[&seeds[..]]; + + let mut withdrawn_quote: u64 = 0; + let mut withdrawn_base: u64 = 0; + + // Withdraw quote tokens if requested + if let Some(amount) = quote_amount { + require!(amount > 0, RedemptionError::InvalidAmount); + require!( + ctx.accounts.vault_quote_ata.amount >= amount, + RedemptionError::InsufficientVaultBalance + ); + + let cpi_accounts = Transfer { + from: ctx.accounts.vault_quote_ata.to_account_info(), + to: ctx.accounts.admin_quote_ata.to_account_info(), + authority: ctx.accounts.vault.to_account_info(), + }; + let cpi_ctx = CpiContext::new_with_signer( + ctx.accounts.token_program.to_account_info(), + cpi_accounts, + signer_seeds, + ); + token::transfer(cpi_ctx, amount)?; + withdrawn_quote = amount; + } + + // Withdraw base tokens if requested (tokens collected from redemptions) + if let Some(amount) = base_amount { + require!(amount > 0, RedemptionError::InvalidAmount); + require!( + ctx.accounts.vault_base_ata.amount >= amount, + RedemptionError::InsufficientVaultBalance + ); + + let cpi_accounts = Transfer { + from: ctx.accounts.vault_base_ata.to_account_info(), + to: ctx.accounts.admin_base_ata.to_account_info(), + authority: ctx.accounts.vault.to_account_info(), + }; + let cpi_ctx = CpiContext::new_with_signer( + ctx.accounts.token_program.to_account_info(), + cpi_accounts, + signer_seeds, + ); + token::transfer(cpi_ctx, amount)?; + withdrawn_base = amount; + } + + emit!(AdminWithdrawal { + vault: ctx.accounts.vault.key(), + admin: ctx.accounts.admin.key(), + quote_amount: withdrawn_quote, + base_amount: withdrawn_base, + }); + + Ok(()) +} diff --git a/programs/redemption/src/lib.rs b/programs/redemption/src/lib.rs index 0e100c2..0de2b77 100644 --- a/programs/redemption/src/lib.rs +++ b/programs/redemption/src/lib.rs @@ -27,8 +27,49 @@ pub mod state; pub use constants::*; pub use errors::*; +pub use instructions::*; +pub use state::*; #[program] pub mod redemption { - // TODO: Add instructions + use super::*; + + /// Initialize a new redemption vault + /// + /// # Arguments + /// * `price` - Quote tokens per base token (scaled by base decimals) + /// * `initial_deposit` - Amount of quote tokens to deposit initially + pub fn initialize(ctx: Context, price: u64, initial_deposit: u64) -> Result<()> { + instructions::initialize::initialize_handler(ctx, price, initial_deposit) + } + + /// Deposit additional quote tokens into the vault (admin only) + /// + /// # Arguments + /// * `amount` - Amount of quote tokens to deposit + pub fn deposit(ctx: Context, amount: u64) -> Result<()> { + instructions::deposit::deposit_handler(ctx, amount) + } + + /// Withdraw tokens from the vault (admin only) + /// Can withdraw both quote tokens and collected base tokens + /// + /// # Arguments + /// * `quote_amount` - Optional amount of quote tokens to withdraw + /// * `base_amount` - Optional amount of base tokens to withdraw + pub fn withdraw( + ctx: Context, + quote_amount: Option, + base_amount: Option, + ) -> Result<()> { + instructions::withdraw::withdraw_handler(ctx, quote_amount, base_amount) + } + + /// Redeem base tokens for quote tokens at the set price + /// + /// # Arguments + /// * `base_amount` - Amount of base tokens to redeem + pub fn redeem(ctx: Context, base_amount: u64) -> Result<()> { + instructions::redeem::redeem_handler(ctx, base_amount) + } } diff --git a/programs/redemption/src/state.rs b/programs/redemption/src/state.rs index 741394c..7b76db8 100644 --- a/programs/redemption/src/state.rs +++ b/programs/redemption/src/state.rs @@ -16,4 +16,29 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -// TODO: Add state accounts +use anchor_lang::prelude::*; + +/// The redemption vault account that holds configuration and state +#[account] +#[derive(InitSpace)] +pub struct RedemptionVault { + /// Version for future upgrades + pub version: u8, + /// Bump seed for PDA + pub bump: u8, + /// Admin who controls the vault + pub admin: Pubkey, + /// The token users send in (base mint) + pub base_mint: Pubkey, + /// The token users receive (quote mint) + pub quote_mint: Pubkey, + /// Price: how many quote tokens per base token (scaled by base decimals) + /// e.g., if price = 1_000_000 and base has 6 decimals, 1 base = 1 quote + pub price: u64, + /// Base mint decimals (cached for calculations) + pub base_decimals: u8, + /// Quote mint decimals (cached for calculations) + pub quote_decimals: u8, + /// Total base tokens redeemed (for tracking) + pub total_redeemed: u64, +} From 82b12a45749f5e58702a8beb0c180a6fb7d529c2 Mon Sep 17 00:00:00 2001 From: Alex Janiak Date: Tue, 17 Feb 2026 10:31:23 -0500 Subject: [PATCH 03/19] refactor: simplify redemption contract - Remove deposit instruction (use initialize once) - Remove tracking stats - Slim down state, errors, constants - Cleaner code structure --- programs/redemption/src/constants.rs | 24 +-- programs/redemption/src/errors.rs | 38 +--- .../redemption/src/instructions/deposit.rs | 90 --------- .../redemption/src/instructions/initialize.rs | 77 ++------ programs/redemption/src/instructions/mod.rs | 19 +- .../redemption/src/instructions/redeem.rs | 172 ++++-------------- .../redemption/src/instructions/withdraw.rs | 138 ++++---------- programs/redemption/src/lib.rs | 53 +----- programs/redemption/src/state.rs | 31 +--- 9 files changed, 108 insertions(+), 534 deletions(-) delete mode 100644 programs/redemption/src/instructions/deposit.rs diff --git a/programs/redemption/src/constants.rs b/programs/redemption/src/constants.rs index d9c522b..2bce1db 100644 --- a/programs/redemption/src/constants.rs +++ b/programs/redemption/src/constants.rs @@ -1,25 +1,5 @@ /* * Copyright (C) 2025 Spice Finance Inc. - * - * This file is part of Z Combinator. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * Licensed under AGPL-3.0 — see LICENSE */ -use anchor_lang::prelude::*; - -#[constant] -pub const REDEMPTION_VERSION: u8 = 1; - -#[constant] -pub const VAULT_SEED: &[u8] = b"redemption_vault"; +pub const VAULT_SEED: &[u8] = b"redemption"; diff --git a/programs/redemption/src/errors.rs b/programs/redemption/src/errors.rs index 6b6fc66..ba06ce4 100644 --- a/programs/redemption/src/errors.rs +++ b/programs/redemption/src/errors.rs @@ -1,43 +1,17 @@ /* * Copyright (C) 2025 Spice Finance Inc. - * - * This file is part of Z Combinator. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * Licensed under AGPL-3.0 — see LICENSE */ use anchor_lang::prelude::*; #[error_code] pub enum RedemptionError { - #[msg("Unauthorized: only admin can perform this action")] + #[msg("Unauthorized")] Unauthorized, - - #[msg("Invalid amount: must be greater than zero")] + #[msg("Invalid amount")] InvalidAmount, - - #[msg("Invalid price: must be greater than zero")] - InvalidPrice, - - #[msg("Insufficient vault balance: not enough quote tokens to fulfill redemption")] - InsufficientVaultBalance, - - #[msg("Arithmetic overflow occurred")] + #[msg("Insufficient vault balance")] + InsufficientBalance, + #[msg("Overflow")] Overflow, - - #[msg("Arithmetic underflow occurred")] - Underflow, - - #[msg("Quote amount too small: redemption would yield zero tokens")] - QuoteAmountTooSmall, } diff --git a/programs/redemption/src/instructions/deposit.rs b/programs/redemption/src/instructions/deposit.rs deleted file mode 100644 index 818bedd..0000000 --- a/programs/redemption/src/instructions/deposit.rs +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2025 Spice Finance Inc. - * - * This file is part of Z Combinator. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -use anchor_lang::prelude::*; -use anchor_spl::associated_token::AssociatedToken; -use anchor_spl::token::{self, Mint, Token, TokenAccount, Transfer}; - -use crate::constants::*; -use crate::errors::RedemptionError; -use crate::state::RedemptionVault; - -#[event] -pub struct QuoteDeposited { - pub vault: Pubkey, - pub admin: Pubkey, - pub amount: u64, -} - -#[derive(Accounts)] -pub struct Deposit<'info> { - /// Admin depositing more quote tokens - #[account(mut)] - pub admin: Signer<'info>, - - /// The redemption vault - #[account( - mut, - seeds = [VAULT_SEED, vault.base_mint.as_ref(), vault.quote_mint.as_ref()], - bump = vault.bump, - constraint = vault.admin == admin.key() @ RedemptionError::Unauthorized, - )] - pub vault: Account<'info, RedemptionVault>, - - pub quote_mint: Account<'info, Mint>, - - /// Vault's quote token account - #[account( - mut, - associated_token::mint = quote_mint, - associated_token::authority = vault, - )] - pub vault_quote_ata: Account<'info, TokenAccount>, - - /// Admin's quote token account - #[account( - mut, - associated_token::mint = quote_mint, - associated_token::authority = admin, - )] - pub admin_quote_ata: Account<'info, TokenAccount>, - - pub token_program: Program<'info, Token>, - pub associated_token_program: Program<'info, AssociatedToken>, -} - -pub fn deposit_handler(ctx: Context, amount: u64) -> Result<()> { - require!(amount > 0, RedemptionError::InvalidAmount); - - // Transfer quote tokens from admin to vault - let cpi_accounts = Transfer { - from: ctx.accounts.admin_quote_ata.to_account_info(), - to: ctx.accounts.vault_quote_ata.to_account_info(), - authority: ctx.accounts.admin.to_account_info(), - }; - let cpi_ctx = CpiContext::new(ctx.accounts.token_program.to_account_info(), cpi_accounts); - token::transfer(cpi_ctx, amount)?; - - emit!(QuoteDeposited { - vault: ctx.accounts.vault.key(), - admin: ctx.accounts.admin.key(), - amount, - }); - - Ok(()) -} diff --git a/programs/redemption/src/instructions/initialize.rs b/programs/redemption/src/instructions/initialize.rs index 882f2b1..d6815bd 100644 --- a/programs/redemption/src/instructions/initialize.rs +++ b/programs/redemption/src/instructions/initialize.rs @@ -1,20 +1,6 @@ /* * Copyright (C) 2025 Spice Finance Inc. - * - * This file is part of Z Combinator. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * Licensed under AGPL-3.0 — see LICENSE */ use anchor_lang::prelude::*; use anchor_spl::associated_token::AssociatedToken; @@ -24,23 +10,11 @@ use crate::constants::*; use crate::errors::RedemptionError; use crate::state::RedemptionVault; -#[event] -pub struct VaultInitialized { - pub vault: Pubkey, - pub admin: Pubkey, - pub base_mint: Pubkey, - pub quote_mint: Pubkey, - pub price: u64, - pub initial_deposit: u64, -} - #[derive(Accounts)] pub struct Initialize<'info> { - /// Admin who will control the vault #[account(mut)] pub admin: Signer<'info>, - /// The redemption vault PDA #[account( init, payer = admin, @@ -50,13 +24,9 @@ pub struct Initialize<'info> { )] pub vault: Account<'info, RedemptionVault>, - /// The token users will send (base mint) pub base_mint: Account<'info, Mint>, - - /// The token users will receive (quote mint) pub quote_mint: Account<'info, Mint>, - /// Vault's ATA for holding quote tokens #[account( init, payer = admin, @@ -65,7 +35,6 @@ pub struct Initialize<'info> { )] pub vault_quote_ata: Account<'info, TokenAccount>, - /// Vault's ATA for receiving base tokens (burn destination) #[account( init, payer = admin, @@ -74,7 +43,6 @@ pub struct Initialize<'info> { )] pub vault_base_ata: Account<'info, TokenAccount>, - /// Admin's quote token account (source of initial deposit) #[account( mut, associated_token::mint = quote_mint, @@ -87,43 +55,26 @@ pub struct Initialize<'info> { pub associated_token_program: Program<'info, AssociatedToken>, } -pub fn initialize_handler( - ctx: Context, - price: u64, - initial_deposit: u64, -) -> Result<()> { - require!(price > 0, RedemptionError::InvalidPrice); - require!(initial_deposit > 0, RedemptionError::InvalidAmount); +pub fn initialize_handler(ctx: Context, price: u64, deposit: u64) -> Result<()> { + require!(price > 0 && deposit > 0, RedemptionError::InvalidAmount); let vault = &mut ctx.accounts.vault; - - vault.version = REDEMPTION_VERSION; vault.bump = ctx.bumps.vault; vault.admin = ctx.accounts.admin.key(); vault.base_mint = ctx.accounts.base_mint.key(); vault.quote_mint = ctx.accounts.quote_mint.key(); vault.price = price; vault.base_decimals = ctx.accounts.base_mint.decimals; - vault.quote_decimals = ctx.accounts.quote_mint.decimals; - vault.total_redeemed = 0; - - // Transfer initial quote tokens from admin to vault - let cpi_accounts = Transfer { - from: ctx.accounts.admin_quote_ata.to_account_info(), - to: ctx.accounts.vault_quote_ata.to_account_info(), - authority: ctx.accounts.admin.to_account_info(), - }; - let cpi_ctx = CpiContext::new(ctx.accounts.token_program.to_account_info(), cpi_accounts); - token::transfer(cpi_ctx, initial_deposit)?; - - emit!(VaultInitialized { - vault: vault.key(), - admin: vault.admin, - base_mint: vault.base_mint, - quote_mint: vault.quote_mint, - price, - initial_deposit, - }); - Ok(()) + token::transfer( + CpiContext::new( + ctx.accounts.token_program.to_account_info(), + Transfer { + from: ctx.accounts.admin_quote_ata.to_account_info(), + to: ctx.accounts.vault_quote_ata.to_account_info(), + authority: ctx.accounts.admin.to_account_info(), + }, + ), + deposit, + ) } diff --git a/programs/redemption/src/instructions/mod.rs b/programs/redemption/src/instructions/mod.rs index 58a3ec8..8a0fb96 100644 --- a/programs/redemption/src/instructions/mod.rs +++ b/programs/redemption/src/instructions/mod.rs @@ -1,28 +1,11 @@ /* * Copyright (C) 2025 Spice Finance Inc. - * - * This file is part of Z Combinator. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * Licensed under AGPL-3.0 — see LICENSE */ - -pub mod deposit; pub mod initialize; pub mod redeem; pub mod withdraw; -pub use deposit::*; pub use initialize::*; pub use redeem::*; pub use withdraw::*; diff --git a/programs/redemption/src/instructions/redeem.rs b/programs/redemption/src/instructions/redeem.rs index a3baa48..08fc56e 100644 --- a/programs/redemption/src/instructions/redeem.rs +++ b/programs/redemption/src/instructions/redeem.rs @@ -1,20 +1,6 @@ /* * Copyright (C) 2025 Spice Finance Inc. - * - * This file is part of Z Combinator. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * Licensed under AGPL-3.0 — see LICENSE */ use anchor_lang::prelude::*; use anchor_spl::associated_token::AssociatedToken; @@ -24,23 +10,12 @@ use crate::constants::*; use crate::errors::RedemptionError; use crate::state::RedemptionVault; -#[event] -pub struct TokensRedeemed { - pub vault: Pubkey, - pub user: Pubkey, - pub base_amount: u64, - pub quote_amount: u64, -} - #[derive(Accounts)] pub struct Redeem<'info> { - /// User redeeming tokens #[account(mut)] pub user: Signer<'info>, - /// The redemption vault #[account( - mut, seeds = [VAULT_SEED, vault.base_mint.as_ref(), vault.quote_mint.as_ref()], bump = vault.bump, )] @@ -49,31 +24,15 @@ pub struct Redeem<'info> { pub base_mint: Account<'info, Mint>, pub quote_mint: Account<'info, Mint>, - /// Vault's quote token account (source) - #[account( - mut, - associated_token::mint = quote_mint, - associated_token::authority = vault, - )] + #[account(mut, associated_token::mint = quote_mint, associated_token::authority = vault)] pub vault_quote_ata: Account<'info, TokenAccount>, - /// Vault's base token account (receives user's base tokens) - #[account( - mut, - associated_token::mint = base_mint, - associated_token::authority = vault, - )] + #[account(mut, associated_token::mint = base_mint, associated_token::authority = vault)] pub vault_base_ata: Account<'info, TokenAccount>, - /// User's base token account (source - tokens being redeemed) - #[account( - mut, - associated_token::mint = base_mint, - associated_token::authority = user, - )] + #[account(mut, associated_token::mint = base_mint, associated_token::authority = user)] pub user_base_ata: Account<'info, TokenAccount>, - /// User's quote token account (destination - tokens being received) #[account( init_if_needed, payer = user, @@ -87,107 +46,54 @@ pub struct Redeem<'info> { pub associated_token_program: Program<'info, AssociatedToken>, } -/// Calculate quote amount from base amount -/// Formula: quote_amount = (base_amount * price) / 10^base_decimals -/// This normalizes for different decimal places between tokens -fn calculate_quote_amount( - base_amount: u64, - price: u64, - base_decimals: u8, -) -> Result { - // Use u128 for intermediate calculation to prevent overflow - let base_amount_u128 = base_amount as u128; - let price_u128 = price as u128; - let divisor = 10u128.pow(base_decimals as u32); - - let quote_amount_u128 = base_amount_u128 - .checked_mul(price_u128) - .ok_or(RedemptionError::Overflow)? - .checked_div(divisor) - .ok_or(RedemptionError::Overflow)?; - - // Ensure result fits in u64 - if quote_amount_u128 > u64::MAX as u128 { - return Err(RedemptionError::Overflow.into()); - } - - Ok(quote_amount_u128 as u64) -} - pub fn redeem_handler(ctx: Context, base_amount: u64) -> Result<()> { require!(base_amount > 0, RedemptionError::InvalidAmount); let vault = &ctx.accounts.vault; - // Calculate how much quote the user should receive - let quote_amount = calculate_quote_amount( - base_amount, - vault.price, - vault.base_decimals, - )?; - - // Ensure the redemption yields a non-zero amount - require!(quote_amount > 0, RedemptionError::QuoteAmountTooSmall); + // quote = base * price / 10^decimals + let quote_amount = (base_amount as u128) + .checked_mul(vault.price as u128) + .and_then(|v| v.checked_div(10u128.pow(vault.base_decimals as u32))) + .and_then(|v| u64::try_from(v).ok()) + .ok_or(RedemptionError::Overflow)?; - // Check vault has sufficient quote tokens BEFORE any transfers + require!(quote_amount > 0, RedemptionError::InvalidAmount); require!( ctx.accounts.vault_quote_ata.amount >= quote_amount, - RedemptionError::InsufficientVaultBalance - ); - - // Check user has sufficient base tokens - require!( - ctx.accounts.user_base_ata.amount >= base_amount, - RedemptionError::InvalidAmount + RedemptionError::InsufficientBalance ); - // Transfer base tokens from user to vault - let cpi_accounts = Transfer { - from: ctx.accounts.user_base_ata.to_account_info(), - to: ctx.accounts.vault_base_ata.to_account_info(), - authority: ctx.accounts.user.to_account_info(), - }; - let cpi_ctx = CpiContext::new(ctx.accounts.token_program.to_account_info(), cpi_accounts); - token::transfer(cpi_ctx, base_amount)?; - - // Transfer quote tokens from vault to user (PDA signed) - let base_mint_key = vault.base_mint; - let quote_mint_key = vault.quote_mint; - let bump = vault.bump; + // User sends base to vault + token::transfer( + CpiContext::new( + ctx.accounts.token_program.to_account_info(), + Transfer { + from: ctx.accounts.user_base_ata.to_account_info(), + to: ctx.accounts.vault_base_ata.to_account_info(), + authority: ctx.accounts.user.to_account_info(), + }, + ), + base_amount, + )?; + // Vault sends quote to user let seeds = &[ VAULT_SEED, - base_mint_key.as_ref(), - quote_mint_key.as_ref(), - &[bump], + vault.base_mint.as_ref(), + vault.quote_mint.as_ref(), + &[vault.bump], ]; - let signer_seeds = &[&seeds[..]]; - - let cpi_accounts = Transfer { - from: ctx.accounts.vault_quote_ata.to_account_info(), - to: ctx.accounts.user_quote_ata.to_account_info(), - authority: ctx.accounts.vault.to_account_info(), - }; - let cpi_ctx = CpiContext::new_with_signer( - ctx.accounts.token_program.to_account_info(), - cpi_accounts, - signer_seeds, - ); - token::transfer(cpi_ctx, quote_amount)?; - - // Update stats - let vault = &mut ctx.accounts.vault; - vault.total_redeemed = vault - .total_redeemed - .checked_add(base_amount) - .ok_or(RedemptionError::Overflow)?; - - emit!(TokensRedeemed { - vault: ctx.accounts.vault.key(), - user: ctx.accounts.user.key(), - base_amount, + token::transfer( + CpiContext::new_with_signer( + ctx.accounts.token_program.to_account_info(), + Transfer { + from: ctx.accounts.vault_quote_ata.to_account_info(), + to: ctx.accounts.user_quote_ata.to_account_info(), + authority: ctx.accounts.vault.to_account_info(), + }, + &[&seeds[..]], + ), quote_amount, - }); - - Ok(()) + ) } diff --git a/programs/redemption/src/instructions/withdraw.rs b/programs/redemption/src/instructions/withdraw.rs index 00a65a6..9f70050 100644 --- a/programs/redemption/src/instructions/withdraw.rs +++ b/programs/redemption/src/instructions/withdraw.rs @@ -1,20 +1,6 @@ /* * Copyright (C) 2025 Spice Finance Inc. - * - * This file is part of Z Combinator. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * Licensed under AGPL-3.0 — see LICENSE */ use anchor_lang::prelude::*; use anchor_spl::associated_token::AssociatedToken; @@ -24,23 +10,12 @@ use crate::constants::*; use crate::errors::RedemptionError; use crate::state::RedemptionVault; -#[event] -pub struct AdminWithdrawal { - pub vault: Pubkey, - pub admin: Pubkey, - pub quote_amount: u64, - pub base_amount: u64, -} - #[derive(Accounts)] pub struct Withdraw<'info> { - /// Admin withdrawing funds #[account(mut)] pub admin: Signer<'info>, - /// The redemption vault #[account( - mut, seeds = [VAULT_SEED, vault.base_mint.as_ref(), vault.quote_mint.as_ref()], bump = vault.bump, constraint = vault.admin == admin.key() @ RedemptionError::Unauthorized, @@ -50,23 +25,12 @@ pub struct Withdraw<'info> { pub base_mint: Account<'info, Mint>, pub quote_mint: Account<'info, Mint>, - /// Vault's quote token account - #[account( - mut, - associated_token::mint = quote_mint, - associated_token::authority = vault, - )] + #[account(mut, associated_token::mint = quote_mint, associated_token::authority = vault)] pub vault_quote_ata: Account<'info, TokenAccount>, - /// Vault's base token account (collected from redemptions) - #[account( - mut, - associated_token::mint = base_mint, - associated_token::authority = vault, - )] + #[account(mut, associated_token::mint = base_mint, associated_token::authority = vault)] pub vault_base_ata: Account<'info, TokenAccount>, - /// Admin's quote token account #[account( init_if_needed, payer = admin, @@ -75,7 +39,6 @@ pub struct Withdraw<'info> { )] pub admin_quote_ata: Account<'info, TokenAccount>, - /// Admin's base token account #[account( init_if_needed, payer = admin, @@ -89,77 +52,52 @@ pub struct Withdraw<'info> { pub associated_token_program: Program<'info, AssociatedToken>, } -pub fn withdraw_handler( - ctx: Context, - quote_amount: Option, - base_amount: Option, -) -> Result<()> { - let vault = &ctx.accounts.vault; - let base_mint_key = vault.base_mint; - let quote_mint_key = vault.quote_mint; - let bump = vault.bump; - +pub fn withdraw_handler(ctx: Context, quote_amount: u64, base_amount: u64) -> Result<()> { let seeds = &[ VAULT_SEED, - base_mint_key.as_ref(), - quote_mint_key.as_ref(), - &[bump], + ctx.accounts.vault.base_mint.as_ref(), + ctx.accounts.vault.quote_mint.as_ref(), + &[ctx.accounts.vault.bump], ]; - let signer_seeds = &[&seeds[..]]; - - let mut withdrawn_quote: u64 = 0; - let mut withdrawn_base: u64 = 0; + let signer = &[&seeds[..]]; - // Withdraw quote tokens if requested - if let Some(amount) = quote_amount { - require!(amount > 0, RedemptionError::InvalidAmount); + if quote_amount > 0 { require!( - ctx.accounts.vault_quote_ata.amount >= amount, - RedemptionError::InsufficientVaultBalance - ); - - let cpi_accounts = Transfer { - from: ctx.accounts.vault_quote_ata.to_account_info(), - to: ctx.accounts.admin_quote_ata.to_account_info(), - authority: ctx.accounts.vault.to_account_info(), - }; - let cpi_ctx = CpiContext::new_with_signer( - ctx.accounts.token_program.to_account_info(), - cpi_accounts, - signer_seeds, + ctx.accounts.vault_quote_ata.amount >= quote_amount, + RedemptionError::InsufficientBalance ); - token::transfer(cpi_ctx, amount)?; - withdrawn_quote = amount; + token::transfer( + CpiContext::new_with_signer( + ctx.accounts.token_program.to_account_info(), + Transfer { + from: ctx.accounts.vault_quote_ata.to_account_info(), + to: ctx.accounts.admin_quote_ata.to_account_info(), + authority: ctx.accounts.vault.to_account_info(), + }, + signer, + ), + quote_amount, + )?; } - // Withdraw base tokens if requested (tokens collected from redemptions) - if let Some(amount) = base_amount { - require!(amount > 0, RedemptionError::InvalidAmount); + if base_amount > 0 { require!( - ctx.accounts.vault_base_ata.amount >= amount, - RedemptionError::InsufficientVaultBalance + ctx.accounts.vault_base_ata.amount >= base_amount, + RedemptionError::InsufficientBalance ); - - let cpi_accounts = Transfer { - from: ctx.accounts.vault_base_ata.to_account_info(), - to: ctx.accounts.admin_base_ata.to_account_info(), - authority: ctx.accounts.vault.to_account_info(), - }; - let cpi_ctx = CpiContext::new_with_signer( - ctx.accounts.token_program.to_account_info(), - cpi_accounts, - signer_seeds, - ); - token::transfer(cpi_ctx, amount)?; - withdrawn_base = amount; + token::transfer( + CpiContext::new_with_signer( + ctx.accounts.token_program.to_account_info(), + Transfer { + from: ctx.accounts.vault_base_ata.to_account_info(), + to: ctx.accounts.admin_base_ata.to_account_info(), + authority: ctx.accounts.vault.to_account_info(), + }, + signer, + ), + base_amount, + )?; } - emit!(AdminWithdrawal { - vault: ctx.accounts.vault.key(), - admin: ctx.accounts.admin.key(), - quote_amount: withdrawn_quote, - base_amount: withdrawn_base, - }); - Ok(()) } diff --git a/programs/redemption/src/lib.rs b/programs/redemption/src/lib.rs index 0de2b77..3e77c80 100644 --- a/programs/redemption/src/lib.rs +++ b/programs/redemption/src/lib.rs @@ -1,20 +1,6 @@ /* * Copyright (C) 2025 Spice Finance Inc. - * - * This file is part of Z Combinator. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * Licensed under AGPL-3.0 — see LICENSE */ use anchor_lang::prelude::*; @@ -34,42 +20,15 @@ pub use state::*; pub mod redemption { use super::*; - /// Initialize a new redemption vault - /// - /// # Arguments - /// * `price` - Quote tokens per base token (scaled by base decimals) - /// * `initial_deposit` - Amount of quote tokens to deposit initially - pub fn initialize(ctx: Context, price: u64, initial_deposit: u64) -> Result<()> { - instructions::initialize::initialize_handler(ctx, price, initial_deposit) + pub fn initialize(ctx: Context, price: u64, deposit: u64) -> Result<()> { + initialize_handler(ctx, price, deposit) } - /// Deposit additional quote tokens into the vault (admin only) - /// - /// # Arguments - /// * `amount` - Amount of quote tokens to deposit - pub fn deposit(ctx: Context, amount: u64) -> Result<()> { - instructions::deposit::deposit_handler(ctx, amount) + pub fn withdraw(ctx: Context, quote_amount: u64, base_amount: u64) -> Result<()> { + withdraw_handler(ctx, quote_amount, base_amount) } - /// Withdraw tokens from the vault (admin only) - /// Can withdraw both quote tokens and collected base tokens - /// - /// # Arguments - /// * `quote_amount` - Optional amount of quote tokens to withdraw - /// * `base_amount` - Optional amount of base tokens to withdraw - pub fn withdraw( - ctx: Context, - quote_amount: Option, - base_amount: Option, - ) -> Result<()> { - instructions::withdraw::withdraw_handler(ctx, quote_amount, base_amount) - } - - /// Redeem base tokens for quote tokens at the set price - /// - /// # Arguments - /// * `base_amount` - Amount of base tokens to redeem pub fn redeem(ctx: Context, base_amount: u64) -> Result<()> { - instructions::redeem::redeem_handler(ctx, base_amount) + redeem_handler(ctx, base_amount) } } diff --git a/programs/redemption/src/state.rs b/programs/redemption/src/state.rs index 7b76db8..f82faab 100644 --- a/programs/redemption/src/state.rs +++ b/programs/redemption/src/state.rs @@ -1,44 +1,17 @@ /* * Copyright (C) 2025 Spice Finance Inc. - * - * This file is part of Z Combinator. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * Licensed under AGPL-3.0 — see LICENSE */ use anchor_lang::prelude::*; -/// The redemption vault account that holds configuration and state #[account] #[derive(InitSpace)] pub struct RedemptionVault { - /// Version for future upgrades - pub version: u8, - /// Bump seed for PDA pub bump: u8, - /// Admin who controls the vault pub admin: Pubkey, - /// The token users send in (base mint) pub base_mint: Pubkey, - /// The token users receive (quote mint) pub quote_mint: Pubkey, - /// Price: how many quote tokens per base token (scaled by base decimals) - /// e.g., if price = 1_000_000 and base has 6 decimals, 1 base = 1 quote + /// Quote tokens per base token (scaled by 10^base_decimals) pub price: u64, - /// Base mint decimals (cached for calculations) pub base_decimals: u8, - /// Quote mint decimals (cached for calculations) - pub quote_decimals: u8, - /// Total base tokens redeemed (for tracking) - pub total_redeemed: u64, } From c160a6f0747728914e743644d0aaa325fa1a3ae1 Mon Sep 17 00:00:00 2001 From: Alex Janiak Date: Tue, 17 Feb 2026 10:33:57 -0500 Subject: [PATCH 04/19] feat: add nonce to vault, restore license headers - Add nonce field to RedemptionVault for multiple vaults per mint pair - PDA seeds now: [VAULT_SEED, base_mint, quote_mint, nonce] - Restore full AGPL license headers - Add doc comments to handlers --- programs/redemption/src/constants.rs | 17 +++++++++++- programs/redemption/src/errors.rs | 16 ++++++++++- .../redemption/src/instructions/initialize.rs | 27 ++++++++++++++++--- programs/redemption/src/instructions/mod.rs | 16 ++++++++++- .../redemption/src/instructions/redeem.rs | 26 ++++++++++++++---- .../redemption/src/instructions/withdraw.rs | 27 +++++++++++++++---- programs/redemption/src/lib.rs | 23 +++++++++++++--- programs/redemption/src/state.rs | 18 ++++++++++++- 8 files changed, 150 insertions(+), 20 deletions(-) diff --git a/programs/redemption/src/constants.rs b/programs/redemption/src/constants.rs index 2bce1db..8babc17 100644 --- a/programs/redemption/src/constants.rs +++ b/programs/redemption/src/constants.rs @@ -1,5 +1,20 @@ /* * Copyright (C) 2025 Spice Finance Inc. - * Licensed under AGPL-3.0 — see LICENSE + * + * This file is part of Z Combinator. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ + pub const VAULT_SEED: &[u8] = b"redemption"; diff --git a/programs/redemption/src/errors.rs b/programs/redemption/src/errors.rs index ba06ce4..0c8610e 100644 --- a/programs/redemption/src/errors.rs +++ b/programs/redemption/src/errors.rs @@ -1,6 +1,20 @@ /* * Copyright (C) 2025 Spice Finance Inc. - * Licensed under AGPL-3.0 — see LICENSE + * + * This file is part of Z Combinator. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ use anchor_lang::prelude::*; diff --git a/programs/redemption/src/instructions/initialize.rs b/programs/redemption/src/instructions/initialize.rs index d6815bd..ecfd12b 100644 --- a/programs/redemption/src/instructions/initialize.rs +++ b/programs/redemption/src/instructions/initialize.rs @@ -1,6 +1,20 @@ /* * Copyright (C) 2025 Spice Finance Inc. - * Licensed under AGPL-3.0 — see LICENSE + * + * This file is part of Z Combinator. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ use anchor_lang::prelude::*; use anchor_spl::associated_token::AssociatedToken; @@ -11,6 +25,7 @@ use crate::errors::RedemptionError; use crate::state::RedemptionVault; #[derive(Accounts)] +#[instruction(nonce: u16)] pub struct Initialize<'info> { #[account(mut)] pub admin: Signer<'info>, @@ -19,7 +34,7 @@ pub struct Initialize<'info> { init, payer = admin, space = 8 + RedemptionVault::INIT_SPACE, - seeds = [VAULT_SEED, base_mint.key().as_ref(), quote_mint.key().as_ref()], + seeds = [VAULT_SEED, base_mint.key().as_ref(), quote_mint.key().as_ref(), &nonce.to_le_bytes()], bump, )] pub vault: Account<'info, RedemptionVault>, @@ -27,6 +42,7 @@ pub struct Initialize<'info> { pub base_mint: Account<'info, Mint>, pub quote_mint: Account<'info, Mint>, + /// Vault's ATA for holding quote tokens (what users receive) #[account( init, payer = admin, @@ -35,6 +51,7 @@ pub struct Initialize<'info> { )] pub vault_quote_ata: Account<'info, TokenAccount>, + /// Vault's ATA for collecting base tokens (what users send) #[account( init, payer = admin, @@ -43,6 +60,7 @@ pub struct Initialize<'info> { )] pub vault_base_ata: Account<'info, TokenAccount>, + /// Admin's quote token account (source of initial deposit) #[account( mut, associated_token::mint = quote_mint, @@ -55,17 +73,20 @@ pub struct Initialize<'info> { pub associated_token_program: Program<'info, AssociatedToken>, } -pub fn initialize_handler(ctx: Context, price: u64, deposit: u64) -> Result<()> { +/// Initialize a new redemption vault with a price and initial quote deposit +pub fn initialize_handler(ctx: Context, nonce: u16, price: u64, deposit: u64) -> Result<()> { require!(price > 0 && deposit > 0, RedemptionError::InvalidAmount); let vault = &mut ctx.accounts.vault; vault.bump = ctx.bumps.vault; + vault.nonce = nonce; vault.admin = ctx.accounts.admin.key(); vault.base_mint = ctx.accounts.base_mint.key(); vault.quote_mint = ctx.accounts.quote_mint.key(); vault.price = price; vault.base_decimals = ctx.accounts.base_mint.decimals; + // Transfer initial quote tokens from admin to vault token::transfer( CpiContext::new( ctx.accounts.token_program.to_account_info(), diff --git a/programs/redemption/src/instructions/mod.rs b/programs/redemption/src/instructions/mod.rs index 8a0fb96..489518d 100644 --- a/programs/redemption/src/instructions/mod.rs +++ b/programs/redemption/src/instructions/mod.rs @@ -1,6 +1,20 @@ /* * Copyright (C) 2025 Spice Finance Inc. - * Licensed under AGPL-3.0 — see LICENSE + * + * This file is part of Z Combinator. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ pub mod initialize; pub mod redeem; diff --git a/programs/redemption/src/instructions/redeem.rs b/programs/redemption/src/instructions/redeem.rs index 08fc56e..3941a08 100644 --- a/programs/redemption/src/instructions/redeem.rs +++ b/programs/redemption/src/instructions/redeem.rs @@ -1,6 +1,20 @@ /* * Copyright (C) 2025 Spice Finance Inc. - * Licensed under AGPL-3.0 — see LICENSE + * + * This file is part of Z Combinator. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ use anchor_lang::prelude::*; use anchor_spl::associated_token::AssociatedToken; @@ -16,7 +30,7 @@ pub struct Redeem<'info> { pub user: Signer<'info>, #[account( - seeds = [VAULT_SEED, vault.base_mint.as_ref(), vault.quote_mint.as_ref()], + seeds = [VAULT_SEED, vault.base_mint.as_ref(), vault.quote_mint.as_ref(), &vault.nonce.to_le_bytes()], bump = vault.bump, )] pub vault: Account<'info, RedemptionVault>, @@ -46,12 +60,13 @@ pub struct Redeem<'info> { pub associated_token_program: Program<'info, AssociatedToken>, } +/// User redeems base tokens for quote tokens at the vault's price pub fn redeem_handler(ctx: Context, base_amount: u64) -> Result<()> { require!(base_amount > 0, RedemptionError::InvalidAmount); let vault = &ctx.accounts.vault; - // quote = base * price / 10^decimals + // Calculate quote amount: quote = base * price / 10^decimals let quote_amount = (base_amount as u128) .checked_mul(vault.price as u128) .and_then(|v| v.checked_div(10u128.pow(vault.base_decimals as u32))) @@ -64,7 +79,7 @@ pub fn redeem_handler(ctx: Context, base_amount: u64) -> Result<()> { RedemptionError::InsufficientBalance ); - // User sends base to vault + // User sends base tokens to vault token::transfer( CpiContext::new( ctx.accounts.token_program.to_account_info(), @@ -77,11 +92,12 @@ pub fn redeem_handler(ctx: Context, base_amount: u64) -> Result<()> { base_amount, )?; - // Vault sends quote to user + // Vault sends quote tokens to user let seeds = &[ VAULT_SEED, vault.base_mint.as_ref(), vault.quote_mint.as_ref(), + &vault.nonce.to_le_bytes(), &[vault.bump], ]; token::transfer( diff --git a/programs/redemption/src/instructions/withdraw.rs b/programs/redemption/src/instructions/withdraw.rs index 9f70050..8db293a 100644 --- a/programs/redemption/src/instructions/withdraw.rs +++ b/programs/redemption/src/instructions/withdraw.rs @@ -1,6 +1,20 @@ /* * Copyright (C) 2025 Spice Finance Inc. - * Licensed under AGPL-3.0 — see LICENSE + * + * This file is part of Z Combinator. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ use anchor_lang::prelude::*; use anchor_spl::associated_token::AssociatedToken; @@ -16,7 +30,7 @@ pub struct Withdraw<'info> { pub admin: Signer<'info>, #[account( - seeds = [VAULT_SEED, vault.base_mint.as_ref(), vault.quote_mint.as_ref()], + seeds = [VAULT_SEED, vault.base_mint.as_ref(), vault.quote_mint.as_ref(), &vault.nonce.to_le_bytes()], bump = vault.bump, constraint = vault.admin == admin.key() @ RedemptionError::Unauthorized, )] @@ -52,12 +66,15 @@ pub struct Withdraw<'info> { pub associated_token_program: Program<'info, AssociatedToken>, } +/// Admin withdraws quote and/or base tokens from the vault pub fn withdraw_handler(ctx: Context, quote_amount: u64, base_amount: u64) -> Result<()> { + let vault = &ctx.accounts.vault; let seeds = &[ VAULT_SEED, - ctx.accounts.vault.base_mint.as_ref(), - ctx.accounts.vault.quote_mint.as_ref(), - &[ctx.accounts.vault.bump], + vault.base_mint.as_ref(), + vault.quote_mint.as_ref(), + &vault.nonce.to_le_bytes(), + &[vault.bump], ]; let signer = &[&seeds[..]]; diff --git a/programs/redemption/src/lib.rs b/programs/redemption/src/lib.rs index 3e77c80..1aa0ec0 100644 --- a/programs/redemption/src/lib.rs +++ b/programs/redemption/src/lib.rs @@ -1,6 +1,20 @@ /* * Copyright (C) 2025 Spice Finance Inc. - * Licensed under AGPL-3.0 — see LICENSE + * + * This file is part of Z Combinator. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ use anchor_lang::prelude::*; @@ -20,14 +34,17 @@ pub use state::*; pub mod redemption { use super::*; - pub fn initialize(ctx: Context, price: u64, deposit: u64) -> Result<()> { - initialize_handler(ctx, price, deposit) + /// Initialize a new redemption vault + pub fn initialize(ctx: Context, nonce: u16, price: u64, deposit: u64) -> Result<()> { + initialize_handler(ctx, nonce, price, deposit) } + /// Admin withdraws tokens from the vault pub fn withdraw(ctx: Context, quote_amount: u64, base_amount: u64) -> Result<()> { withdraw_handler(ctx, quote_amount, base_amount) } + /// User redeems base tokens for quote tokens pub fn redeem(ctx: Context, base_amount: u64) -> Result<()> { redeem_handler(ctx, base_amount) } diff --git a/programs/redemption/src/state.rs b/programs/redemption/src/state.rs index f82faab..6d674ed 100644 --- a/programs/redemption/src/state.rs +++ b/programs/redemption/src/state.rs @@ -1,13 +1,29 @@ /* * Copyright (C) 2025 Spice Finance Inc. - * Licensed under AGPL-3.0 — see LICENSE + * + * This file is part of Z Combinator. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ use anchor_lang::prelude::*; +/// Redemption vault that holds quote tokens for users to redeem with base tokens #[account] #[derive(InitSpace)] pub struct RedemptionVault { pub bump: u8, + pub nonce: u16, pub admin: Pubkey, pub base_mint: Pubkey, pub quote_mint: Pubkey, From fd8db8d74a7507a83ad62170d74daa87d7b55d15 Mon Sep 17 00:00:00 2001 From: Alex Janiak Date: Tue, 17 Feb 2026 12:03:03 -0500 Subject: [PATCH 05/19] refactor: move VAULT_SEED to state.rs --- programs/redemption/src/constants.rs | 2 +- programs/redemption/src/instructions/initialize.rs | 2 +- programs/redemption/src/instructions/redeem.rs | 2 +- programs/redemption/src/instructions/withdraw.rs | 2 +- programs/redemption/src/lib.rs | 1 - programs/redemption/src/state.rs | 2 ++ 6 files changed, 6 insertions(+), 5 deletions(-) diff --git a/programs/redemption/src/constants.rs b/programs/redemption/src/constants.rs index 8babc17..543e561 100644 --- a/programs/redemption/src/constants.rs +++ b/programs/redemption/src/constants.rs @@ -17,4 +17,4 @@ * along with this program. If not, see . */ -pub const VAULT_SEED: &[u8] = b"redemption"; +// Constants moved to their respective modules diff --git a/programs/redemption/src/instructions/initialize.rs b/programs/redemption/src/instructions/initialize.rs index ecfd12b..1e35426 100644 --- a/programs/redemption/src/instructions/initialize.rs +++ b/programs/redemption/src/instructions/initialize.rs @@ -20,7 +20,7 @@ use anchor_lang::prelude::*; use anchor_spl::associated_token::AssociatedToken; use anchor_spl::token::{self, Mint, Token, TokenAccount, Transfer}; -use crate::constants::*; +use crate::state::VAULT_SEED; use crate::errors::RedemptionError; use crate::state::RedemptionVault; diff --git a/programs/redemption/src/instructions/redeem.rs b/programs/redemption/src/instructions/redeem.rs index 3941a08..d331b47 100644 --- a/programs/redemption/src/instructions/redeem.rs +++ b/programs/redemption/src/instructions/redeem.rs @@ -20,7 +20,7 @@ use anchor_lang::prelude::*; use anchor_spl::associated_token::AssociatedToken; use anchor_spl::token::{self, Mint, Token, TokenAccount, Transfer}; -use crate::constants::*; +use crate::state::VAULT_SEED; use crate::errors::RedemptionError; use crate::state::RedemptionVault; diff --git a/programs/redemption/src/instructions/withdraw.rs b/programs/redemption/src/instructions/withdraw.rs index 8db293a..8b80588 100644 --- a/programs/redemption/src/instructions/withdraw.rs +++ b/programs/redemption/src/instructions/withdraw.rs @@ -20,7 +20,7 @@ use anchor_lang::prelude::*; use anchor_spl::associated_token::AssociatedToken; use anchor_spl::token::{self, Mint, Token, TokenAccount, Transfer}; -use crate::constants::*; +use crate::state::VAULT_SEED; use crate::errors::RedemptionError; use crate::state::RedemptionVault; diff --git a/programs/redemption/src/lib.rs b/programs/redemption/src/lib.rs index 1aa0ec0..ea7ac48 100644 --- a/programs/redemption/src/lib.rs +++ b/programs/redemption/src/lib.rs @@ -25,7 +25,6 @@ pub mod errors; pub mod instructions; pub mod state; -pub use constants::*; pub use errors::*; pub use instructions::*; pub use state::*; diff --git a/programs/redemption/src/state.rs b/programs/redemption/src/state.rs index 6d674ed..1598ef9 100644 --- a/programs/redemption/src/state.rs +++ b/programs/redemption/src/state.rs @@ -18,6 +18,8 @@ */ use anchor_lang::prelude::*; +pub const VAULT_SEED: &[u8] = b"redemption"; + /// Redemption vault that holds quote tokens for users to redeem with base tokens #[account] #[derive(InitSpace)] From b84f43a634840df1b10a5d74f86bac0333facada Mon Sep 17 00:00:00 2001 From: Alex Janiak Date: Tue, 17 Feb 2026 12:04:46 -0500 Subject: [PATCH 06/19] chore: remove empty constants.rs --- programs/redemption/src/constants.rs | 20 -------------------- programs/redemption/src/lib.rs | 1 - 2 files changed, 21 deletions(-) delete mode 100644 programs/redemption/src/constants.rs diff --git a/programs/redemption/src/constants.rs b/programs/redemption/src/constants.rs deleted file mode 100644 index 543e561..0000000 --- a/programs/redemption/src/constants.rs +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) 2025 Spice Finance Inc. - * - * This file is part of Z Combinator. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -// Constants moved to their respective modules diff --git a/programs/redemption/src/lib.rs b/programs/redemption/src/lib.rs index ea7ac48..3bb721b 100644 --- a/programs/redemption/src/lib.rs +++ b/programs/redemption/src/lib.rs @@ -20,7 +20,6 @@ use anchor_lang::prelude::*; declare_id!("rdm5xmgfjVn2WXCNrdEuBDoj3JJHt7K6M82jBnXf1Ef"); -pub mod constants; pub mod errors; pub mod instructions; pub mod state; From b9a82c37ecd01e94fd82e132cfebe350b63540eb Mon Sep 17 00:00:00 2001 From: Alex Janiak Date: Tue, 17 Feb 2026 12:07:03 -0500 Subject: [PATCH 07/19] feat: support Token-2022 via token_interface - Use InterfaceAccount for Mint and TokenAccount - Use Interface for token programs - Separate base_token_program and quote_token_program - Use transfer_checked for all transfers - Store quote_decimals in vault state --- .../redemption/src/instructions/initialize.rs | 32 ++++++---- .../redemption/src/instructions/redeem.rs | 62 ++++++++++++------- .../redemption/src/instructions/withdraw.rs | 54 ++++++++++------ programs/redemption/src/state.rs | 1 + 4 files changed, 96 insertions(+), 53 deletions(-) diff --git a/programs/redemption/src/instructions/initialize.rs b/programs/redemption/src/instructions/initialize.rs index 1e35426..cde9adc 100644 --- a/programs/redemption/src/instructions/initialize.rs +++ b/programs/redemption/src/instructions/initialize.rs @@ -18,11 +18,10 @@ */ use anchor_lang::prelude::*; use anchor_spl::associated_token::AssociatedToken; -use anchor_spl::token::{self, Mint, Token, TokenAccount, Transfer}; +use anchor_spl::token_interface::{self, Mint, TokenAccount, TokenInterface, TransferChecked}; -use crate::state::VAULT_SEED; use crate::errors::RedemptionError; -use crate::state::RedemptionVault; +use crate::state::{RedemptionVault, VAULT_SEED}; #[derive(Accounts)] #[instruction(nonce: u16)] @@ -39,8 +38,8 @@ pub struct Initialize<'info> { )] pub vault: Account<'info, RedemptionVault>, - pub base_mint: Account<'info, Mint>, - pub quote_mint: Account<'info, Mint>, + pub base_mint: InterfaceAccount<'info, Mint>, + pub quote_mint: InterfaceAccount<'info, Mint>, /// Vault's ATA for holding quote tokens (what users receive) #[account( @@ -48,8 +47,9 @@ pub struct Initialize<'info> { payer = admin, associated_token::mint = quote_mint, associated_token::authority = vault, + associated_token::token_program = quote_token_program, )] - pub vault_quote_ata: Account<'info, TokenAccount>, + pub vault_quote_ata: InterfaceAccount<'info, TokenAccount>, /// Vault's ATA for collecting base tokens (what users send) #[account( @@ -57,20 +57,23 @@ pub struct Initialize<'info> { payer = admin, associated_token::mint = base_mint, associated_token::authority = vault, + associated_token::token_program = base_token_program, )] - pub vault_base_ata: Account<'info, TokenAccount>, + pub vault_base_ata: InterfaceAccount<'info, TokenAccount>, /// Admin's quote token account (source of initial deposit) #[account( mut, associated_token::mint = quote_mint, associated_token::authority = admin, + associated_token::token_program = quote_token_program, )] - pub admin_quote_ata: Account<'info, TokenAccount>, + pub admin_quote_ata: InterfaceAccount<'info, TokenAccount>, - pub system_program: Program<'info, System>, - pub token_program: Program<'info, Token>, + pub base_token_program: Interface<'info, TokenInterface>, + pub quote_token_program: Interface<'info, TokenInterface>, pub associated_token_program: Program<'info, AssociatedToken>, + pub system_program: Program<'info, System>, } /// Initialize a new redemption vault with a price and initial quote deposit @@ -85,17 +88,20 @@ pub fn initialize_handler(ctx: Context, nonce: u16, price: u64, depo vault.quote_mint = ctx.accounts.quote_mint.key(); vault.price = price; vault.base_decimals = ctx.accounts.base_mint.decimals; + vault.quote_decimals = ctx.accounts.quote_mint.decimals; // Transfer initial quote tokens from admin to vault - token::transfer( + token_interface::transfer_checked( CpiContext::new( - ctx.accounts.token_program.to_account_info(), - Transfer { + ctx.accounts.quote_token_program.to_account_info(), + TransferChecked { from: ctx.accounts.admin_quote_ata.to_account_info(), + mint: ctx.accounts.quote_mint.to_account_info(), to: ctx.accounts.vault_quote_ata.to_account_info(), authority: ctx.accounts.admin.to_account_info(), }, ), deposit, + ctx.accounts.quote_mint.decimals, ) } diff --git a/programs/redemption/src/instructions/redeem.rs b/programs/redemption/src/instructions/redeem.rs index d331b47..88f5c12 100644 --- a/programs/redemption/src/instructions/redeem.rs +++ b/programs/redemption/src/instructions/redeem.rs @@ -18,11 +18,10 @@ */ use anchor_lang::prelude::*; use anchor_spl::associated_token::AssociatedToken; -use anchor_spl::token::{self, Mint, Token, TokenAccount, Transfer}; +use anchor_spl::token_interface::{self, Mint, TokenAccount, TokenInterface, TransferChecked}; -use crate::state::VAULT_SEED; use crate::errors::RedemptionError; -use crate::state::RedemptionVault; +use crate::state::{RedemptionVault, VAULT_SEED}; #[derive(Accounts)] pub struct Redeem<'info> { @@ -35,29 +34,46 @@ pub struct Redeem<'info> { )] pub vault: Account<'info, RedemptionVault>, - pub base_mint: Account<'info, Mint>, - pub quote_mint: Account<'info, Mint>, + pub base_mint: InterfaceAccount<'info, Mint>, + pub quote_mint: InterfaceAccount<'info, Mint>, - #[account(mut, associated_token::mint = quote_mint, associated_token::authority = vault)] - pub vault_quote_ata: Account<'info, TokenAccount>, + #[account( + mut, + associated_token::mint = quote_mint, + associated_token::authority = vault, + associated_token::token_program = quote_token_program, + )] + pub vault_quote_ata: InterfaceAccount<'info, TokenAccount>, - #[account(mut, associated_token::mint = base_mint, associated_token::authority = vault)] - pub vault_base_ata: Account<'info, TokenAccount>, + #[account( + mut, + associated_token::mint = base_mint, + associated_token::authority = vault, + associated_token::token_program = base_token_program, + )] + pub vault_base_ata: InterfaceAccount<'info, TokenAccount>, - #[account(mut, associated_token::mint = base_mint, associated_token::authority = user)] - pub user_base_ata: Account<'info, TokenAccount>, + #[account( + mut, + associated_token::mint = base_mint, + associated_token::authority = user, + associated_token::token_program = base_token_program, + )] + pub user_base_ata: InterfaceAccount<'info, TokenAccount>, #[account( init_if_needed, payer = user, associated_token::mint = quote_mint, associated_token::authority = user, + associated_token::token_program = quote_token_program, )] - pub user_quote_ata: Account<'info, TokenAccount>, + pub user_quote_ata: InterfaceAccount<'info, TokenAccount>, - pub system_program: Program<'info, System>, - pub token_program: Program<'info, Token>, + pub base_token_program: Interface<'info, TokenInterface>, + pub quote_token_program: Interface<'info, TokenInterface>, pub associated_token_program: Program<'info, AssociatedToken>, + pub system_program: Program<'info, System>, } /// User redeems base tokens for quote tokens at the vault's price @@ -66,7 +82,7 @@ pub fn redeem_handler(ctx: Context, base_amount: u64) -> Result<()> { let vault = &ctx.accounts.vault; - // Calculate quote amount: quote = base * price / 10^decimals + // Calculate quote amount: quote = base * price / 10^base_decimals let quote_amount = (base_amount as u128) .checked_mul(vault.price as u128) .and_then(|v| v.checked_div(10u128.pow(vault.base_decimals as u32))) @@ -80,16 +96,18 @@ pub fn redeem_handler(ctx: Context, base_amount: u64) -> Result<()> { ); // User sends base tokens to vault - token::transfer( + token_interface::transfer_checked( CpiContext::new( - ctx.accounts.token_program.to_account_info(), - Transfer { + ctx.accounts.base_token_program.to_account_info(), + TransferChecked { from: ctx.accounts.user_base_ata.to_account_info(), + mint: ctx.accounts.base_mint.to_account_info(), to: ctx.accounts.vault_base_ata.to_account_info(), authority: ctx.accounts.user.to_account_info(), }, ), base_amount, + ctx.accounts.base_mint.decimals, )?; // Vault sends quote tokens to user @@ -100,16 +118,18 @@ pub fn redeem_handler(ctx: Context, base_amount: u64) -> Result<()> { &vault.nonce.to_le_bytes(), &[vault.bump], ]; - token::transfer( + token_interface::transfer_checked( CpiContext::new_with_signer( - ctx.accounts.token_program.to_account_info(), - Transfer { + ctx.accounts.quote_token_program.to_account_info(), + TransferChecked { from: ctx.accounts.vault_quote_ata.to_account_info(), + mint: ctx.accounts.quote_mint.to_account_info(), to: ctx.accounts.user_quote_ata.to_account_info(), authority: ctx.accounts.vault.to_account_info(), }, &[&seeds[..]], ), quote_amount, + ctx.accounts.quote_mint.decimals, ) } diff --git a/programs/redemption/src/instructions/withdraw.rs b/programs/redemption/src/instructions/withdraw.rs index 8b80588..c88fecb 100644 --- a/programs/redemption/src/instructions/withdraw.rs +++ b/programs/redemption/src/instructions/withdraw.rs @@ -18,11 +18,10 @@ */ use anchor_lang::prelude::*; use anchor_spl::associated_token::AssociatedToken; -use anchor_spl::token::{self, Mint, Token, TokenAccount, Transfer}; +use anchor_spl::token_interface::{self, Mint, TokenAccount, TokenInterface, TransferChecked}; -use crate::state::VAULT_SEED; use crate::errors::RedemptionError; -use crate::state::RedemptionVault; +use crate::state::{RedemptionVault, VAULT_SEED}; #[derive(Accounts)] pub struct Withdraw<'info> { @@ -36,34 +35,47 @@ pub struct Withdraw<'info> { )] pub vault: Account<'info, RedemptionVault>, - pub base_mint: Account<'info, Mint>, - pub quote_mint: Account<'info, Mint>, + pub base_mint: InterfaceAccount<'info, Mint>, + pub quote_mint: InterfaceAccount<'info, Mint>, - #[account(mut, associated_token::mint = quote_mint, associated_token::authority = vault)] - pub vault_quote_ata: Account<'info, TokenAccount>, + #[account( + mut, + associated_token::mint = quote_mint, + associated_token::authority = vault, + associated_token::token_program = quote_token_program, + )] + pub vault_quote_ata: InterfaceAccount<'info, TokenAccount>, - #[account(mut, associated_token::mint = base_mint, associated_token::authority = vault)] - pub vault_base_ata: Account<'info, TokenAccount>, + #[account( + mut, + associated_token::mint = base_mint, + associated_token::authority = vault, + associated_token::token_program = base_token_program, + )] + pub vault_base_ata: InterfaceAccount<'info, TokenAccount>, #[account( init_if_needed, payer = admin, associated_token::mint = quote_mint, associated_token::authority = admin, + associated_token::token_program = quote_token_program, )] - pub admin_quote_ata: Account<'info, TokenAccount>, + pub admin_quote_ata: InterfaceAccount<'info, TokenAccount>, #[account( init_if_needed, payer = admin, associated_token::mint = base_mint, associated_token::authority = admin, + associated_token::token_program = base_token_program, )] - pub admin_base_ata: Account<'info, TokenAccount>, + pub admin_base_ata: InterfaceAccount<'info, TokenAccount>, - pub system_program: Program<'info, System>, - pub token_program: Program<'info, Token>, + pub base_token_program: Interface<'info, TokenInterface>, + pub quote_token_program: Interface<'info, TokenInterface>, pub associated_token_program: Program<'info, AssociatedToken>, + pub system_program: Program<'info, System>, } /// Admin withdraws quote and/or base tokens from the vault @@ -83,17 +95,19 @@ pub fn withdraw_handler(ctx: Context, quote_amount: u64, base_amount: ctx.accounts.vault_quote_ata.amount >= quote_amount, RedemptionError::InsufficientBalance ); - token::transfer( + token_interface::transfer_checked( CpiContext::new_with_signer( - ctx.accounts.token_program.to_account_info(), - Transfer { + ctx.accounts.quote_token_program.to_account_info(), + TransferChecked { from: ctx.accounts.vault_quote_ata.to_account_info(), + mint: ctx.accounts.quote_mint.to_account_info(), to: ctx.accounts.admin_quote_ata.to_account_info(), authority: ctx.accounts.vault.to_account_info(), }, signer, ), quote_amount, + ctx.accounts.quote_mint.decimals, )?; } @@ -102,17 +116,19 @@ pub fn withdraw_handler(ctx: Context, quote_amount: u64, base_amount: ctx.accounts.vault_base_ata.amount >= base_amount, RedemptionError::InsufficientBalance ); - token::transfer( + token_interface::transfer_checked( CpiContext::new_with_signer( - ctx.accounts.token_program.to_account_info(), - Transfer { + ctx.accounts.base_token_program.to_account_info(), + TransferChecked { from: ctx.accounts.vault_base_ata.to_account_info(), + mint: ctx.accounts.base_mint.to_account_info(), to: ctx.accounts.admin_base_ata.to_account_info(), authority: ctx.accounts.vault.to_account_info(), }, signer, ), base_amount, + ctx.accounts.base_mint.decimals, )?; } diff --git a/programs/redemption/src/state.rs b/programs/redemption/src/state.rs index 1598ef9..27e6916 100644 --- a/programs/redemption/src/state.rs +++ b/programs/redemption/src/state.rs @@ -32,4 +32,5 @@ pub struct RedemptionVault { /// Quote tokens per base token (scaled by 10^base_decimals) pub price: u64, pub base_decimals: u8, + pub quote_decimals: u8, } From 7518a50f9e3fb5cb14a25cd56cfb28b5315e6df9 Mon Sep 17 00:00:00 2001 From: Alex Janiak Date: Tue, 17 Feb 2026 12:08:03 -0500 Subject: [PATCH 08/19] docs: add redemption program to README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index f3e5f83..98cf6a9 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ | amm | AMMSgtnttAKx5Ad2Y1socKJ3CcQYCB2ctg8U2SAHcVEx | 0.1.0 | | | vault | VLTEetGyPKtffi1u3Jr8btWATv33NeDyUuRsPENFPTU | 0.1.0 | | | svault | GmH3zEvgmWoC6Y6hxinYYRWLCuxUikRN5SAmVDVF4Jjy | 0.1.0 | | +| redemption | rdm5xmgfjVn2WXCNrdEuBDoj3JJHt7K6M82jBnXf1Ef | 0.1.0 | | | vault | vLTgeZhLgcr4HvBGxKonSnmU4t7qLcgsVcVtUd3haZc | 0.0.0 | ❌ | Fee Authority: FEEnkcCNE2623LYCPtLf63LFzXpCFigBLTu4qZovRGZC From 95173cdc6ca603b7d03e15d1eaf7f0338523f2a8 Mon Sep 17 00:00:00 2001 From: Alex Janiak Date: Tue, 17 Feb 2026 12:45:40 -0500 Subject: [PATCH 09/19] chore: add redemption to smart-deploy script --- scripts/smart-deploy.sh | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/scripts/smart-deploy.sh b/scripts/smart-deploy.sh index 0800968..9a0d630 100755 --- a/scripts/smart-deploy.sh +++ b/scripts/smart-deploy.sh @@ -20,6 +20,7 @@ COL_AMM=$CYAN COL_FUTARCHY=$CYAN COL_VAULT=$CYAN COL_SVAULT=$CYAN +COL_REDEMPTION=$CYAN # Box drawing LINE_H="${DIM}────────────────────────────────────────────────────${NC}" @@ -32,7 +33,7 @@ DEPLOY_DIR="$ROOT_DIR/target/deploy" CACHE_DIR="$ROOT_DIR/.deploy-cache" # All programs to deploy -ALL_PROGRAMS=("amm" "futarchy" "vault" "svault") +ALL_PROGRAMS=("amm" "futarchy" "vault" "svault" "redemption") # Default options DRY_RUN=false @@ -84,10 +85,11 @@ log_error() { get_prog_color() { local prog=$1 case "$prog" in - amm) echo "$COL_AMM" ;; - futarchy) echo "$COL_FUTARCHY" ;; - vault) echo "$COL_VAULT" ;; - svault) echo "$COL_SVAULT" ;; + amm) echo "$COL_AMM" ;; + futarchy) echo "$COL_FUTARCHY" ;; + vault) echo "$COL_VAULT" ;; + svault) echo "$COL_SVAULT" ;; + redemption) echo "$COL_REDEMPTION" ;; *) echo "$CYAN" ;; esac } From c87eb5830f0dd8065c73906604d2d18aad963975 Mon Sep 17 00:00:00 2001 From: Alex Janiak Date: Tue, 17 Feb 2026 12:58:26 -0500 Subject: [PATCH 10/19] test: add redemption devnet test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tests: - Initialize vault (9-dec base, 6-dec quote, 0.0002758 price) - Redeem 1M base → ~275.8 quote - InsufficientBalance error when over-redeeming - Admin withdrawal of remaining funds --- Anchor.toml | 1 + tests/redemption/devnet-test.ts | 337 ++++++++++++++++++++++++++++++++ 2 files changed, 338 insertions(+) create mode 100644 tests/redemption/devnet-test.ts diff --git a/Anchor.toml b/Anchor.toml index 4ae0754..721449a 100644 --- a/Anchor.toml +++ b/Anchor.toml @@ -41,3 +41,4 @@ test-dao = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 \"tests/dao/**/*.ts\ test-fut = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 \"tests/futarchy/**/*.ts\"" test-vault = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 \"tests/vault/**/*.ts\"" test-svault = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 \"tests/svault/**/*.ts\"" +test-redemption = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 \"tests/redemption/**/*.ts\"" diff --git a/tests/redemption/devnet-test.ts b/tests/redemption/devnet-test.ts new file mode 100644 index 0000000..b2cac07 --- /dev/null +++ b/tests/redemption/devnet-test.ts @@ -0,0 +1,337 @@ +/** + * Redemption Program - Devnet Test + * + * Tests: + * 1. Initialize vault with 9-decimal base, 6-decimal quote (USDC-like) + * 2. Redeem 1M base tokens at 0.0002758 price → ~275.8 quote + * 3. Error when redeeming more than vault balance + * 4. Admin withdraws leftover quote + */ + +import * as anchor from "@coral-xyz/anchor"; +import { Program } from "@coral-xyz/anchor"; +import { + PublicKey, + Keypair, + SystemProgram, + LAMPORTS_PER_SOL, +} from "@solana/web3.js"; +import { + createMint, + mintTo, + getOrCreateAssociatedTokenAccount, + getAssociatedTokenAddress, + TOKEN_PROGRAM_ID, + ASSOCIATED_TOKEN_PROGRAM_ID, +} from "@solana/spl-token"; +import { expect } from "chai"; + +// IDL will be loaded by Anchor +import { Redemption } from "../../target/types/redemption"; + +const VAULT_SEED = Buffer.from("redemption"); + +// Test parameters +const BASE_DECIMALS = 9; +const QUOTE_DECIMALS = 6; +const UI_PRICE = 0.0002758; // 0.0002758 quote per base +const PRICE = Math.round(UI_PRICE * 10 ** QUOTE_DECIMALS); // 276 + +const UI_REDEEM_AMOUNT = 1_000_000; // 1 million base tokens +const RAW_REDEEM_AMOUNT = UI_REDEEM_AMOUNT * 10 ** BASE_DECIMALS; +const EXPECTED_QUOTE = Math.floor( + (RAW_REDEEM_AMOUNT * PRICE) / 10 ** BASE_DECIMALS +); // ~275,800,000 raw = 275.8 USDC + +// Initial vault deposit (enough for the test + some extra) +const INITIAL_QUOTE_DEPOSIT = 500 * 10 ** QUOTE_DECIMALS; // 500 quote tokens + +describe("Redemption - Devnet Test", () => { + const provider = anchor.AnchorProvider.env(); + anchor.setProvider(provider); + + const program = anchor.workspace.Redemption as Program; + const admin = provider.wallet as anchor.Wallet; + + let baseMint: PublicKey; + let quoteMint: PublicKey; + let vault: PublicKey; + let vaultBump: number; + let vaultQuoteAta: PublicKey; + let vaultBaseAta: PublicKey; + let adminQuoteAta: PublicKey; + let adminBaseAta: PublicKey; + let userKeypair: Keypair; + let userBaseAta: PublicKey; + let userQuoteAta: PublicKey; + + const nonce = Math.floor(Math.random() * 65535); // Random nonce for unique vault + + before(async () => { + console.log("\n=== Setup ==="); + console.log(`Program ID: ${program.programId.toBase58()}`); + console.log(`Admin: ${admin.publicKey.toBase58()}`); + console.log(`Nonce: ${nonce}`); + console.log(`Price: ${PRICE} (${UI_PRICE} UI)`); + + // Create base mint (9 decimals) + baseMint = await createMint( + provider.connection, + admin.payer, + admin.publicKey, + null, + BASE_DECIMALS + ); + console.log(`Base Mint (${BASE_DECIMALS} decimals): ${baseMint.toBase58()}`); + + // Create quote mint (6 decimals, like USDC) + quoteMint = await createMint( + provider.connection, + admin.payer, + admin.publicKey, + null, + QUOTE_DECIMALS + ); + console.log(`Quote Mint (${QUOTE_DECIMALS} decimals): ${quoteMint.toBase58()}`); + + // Derive vault PDA + [vault, vaultBump] = PublicKey.findProgramAddressSync( + [ + VAULT_SEED, + baseMint.toBuffer(), + quoteMint.toBuffer(), + Buffer.from(new Uint16Array([nonce]).buffer), + ], + program.programId + ); + console.log(`Vault PDA: ${vault.toBase58()}`); + + // Get vault ATAs + vaultQuoteAta = await getAssociatedTokenAddress(quoteMint, vault, true); + vaultBaseAta = await getAssociatedTokenAddress(baseMint, vault, true); + + // Setup admin quote ATA and mint tokens for deposit + const adminQuoteAccount = await getOrCreateAssociatedTokenAccount( + provider.connection, + admin.payer, + quoteMint, + admin.publicKey + ); + adminQuoteAta = adminQuoteAccount.address; + + await mintTo( + provider.connection, + admin.payer, + quoteMint, + adminQuoteAta, + admin.publicKey, + INITIAL_QUOTE_DEPOSIT + ); + console.log(`Minted ${INITIAL_QUOTE_DEPOSIT / 10 ** QUOTE_DECIMALS} quote to admin`); + + // Setup test user + userKeypair = Keypair.generate(); + + // Fund user with SOL + const fundTx = await provider.connection.requestAirdrop( + userKeypair.publicKey, + LAMPORTS_PER_SOL + ); + await provider.connection.confirmTransaction(fundTx); + console.log(`User: ${userKeypair.publicKey.toBase58()}`); + + // Setup user base ATA and mint tokens + const userBaseAccount = await getOrCreateAssociatedTokenAccount( + provider.connection, + admin.payer, + baseMint, + userKeypair.publicKey + ); + userBaseAta = userBaseAccount.address; + + // Mint base tokens to user (enough for test) + const userBaseMintAmount = 2_000_000 * 10 ** BASE_DECIMALS; // 2M base tokens + await mintTo( + provider.connection, + admin.payer, + baseMint, + userBaseAta, + admin.publicKey, + userBaseMintAmount + ); + console.log(`Minted ${userBaseMintAmount / 10 ** BASE_DECIMALS} base to user`); + + userQuoteAta = await getAssociatedTokenAddress(quoteMint, userKeypair.publicKey); + }); + + it("initializes vault with price and deposit", async () => { + console.log("\n=== Test: Initialize Vault ==="); + + await program.methods + .initialize(nonce, new anchor.BN(PRICE), new anchor.BN(INITIAL_QUOTE_DEPOSIT)) + .accounts({ + admin: admin.publicKey, + vault, + baseMint, + quoteMint, + vaultQuoteAta, + vaultBaseAta, + adminQuoteAta, + baseTokenProgram: TOKEN_PROGRAM_ID, + quoteTokenProgram: TOKEN_PROGRAM_ID, + associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID, + systemProgram: SystemProgram.programId, + }) + .rpc(); + + // Verify vault state + const vaultAccount = await program.account.redemptionVault.fetch(vault); + expect(vaultAccount.admin.toBase58()).to.equal(admin.publicKey.toBase58()); + expect(vaultAccount.baseMint.toBase58()).to.equal(baseMint.toBase58()); + expect(vaultAccount.quoteMint.toBase58()).to.equal(quoteMint.toBase58()); + expect(vaultAccount.price.toNumber()).to.equal(PRICE); + expect(vaultAccount.nonce).to.equal(nonce); + + // Verify vault quote balance + const vaultQuoteBalance = await provider.connection.getTokenAccountBalance(vaultQuoteAta); + expect(Number(vaultQuoteBalance.value.amount)).to.equal(INITIAL_QUOTE_DEPOSIT); + + console.log(`✓ Vault initialized with ${INITIAL_QUOTE_DEPOSIT / 10 ** QUOTE_DECIMALS} quote tokens`); + console.log(`✓ Price set to ${PRICE} (${UI_PRICE} UI)`); + }); + + it("redeems 1M base tokens for ~275.8 quote", async () => { + console.log("\n=== Test: Redeem 1M Base ==="); + + const userQuoteBalanceBefore = await provider.connection + .getTokenAccountBalance(userQuoteAta) + .catch(() => ({ value: { amount: "0" } })); + + await program.methods + .redeem(new anchor.BN(RAW_REDEEM_AMOUNT)) + .accounts({ + user: userKeypair.publicKey, + vault, + baseMint, + quoteMint, + vaultQuoteAta, + vaultBaseAta, + userBaseAta, + userQuoteAta, + baseTokenProgram: TOKEN_PROGRAM_ID, + quoteTokenProgram: TOKEN_PROGRAM_ID, + associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID, + systemProgram: SystemProgram.programId, + }) + .signers([userKeypair]) + .rpc(); + + // Verify user received quote tokens + const userQuoteBalance = await provider.connection.getTokenAccountBalance(userQuoteAta); + const received = Number(userQuoteBalance.value.amount) - Number(userQuoteBalanceBefore.value.amount); + + console.log(`✓ Redeemed ${UI_REDEEM_AMOUNT.toLocaleString()} base tokens`); + console.log(`✓ Received ${received / 10 ** QUOTE_DECIMALS} quote tokens`); + console.log(`✓ Expected ~${EXPECTED_QUOTE / 10 ** QUOTE_DECIMALS} quote tokens`); + + // Allow small rounding tolerance + expect(received).to.be.closeTo(EXPECTED_QUOTE, 10); + + // Verify vault received base tokens + const vaultBaseBalance = await provider.connection.getTokenAccountBalance(vaultBaseAta); + expect(Number(vaultBaseBalance.value.amount)).to.equal(RAW_REDEEM_AMOUNT); + console.log(`✓ Vault received ${RAW_REDEEM_AMOUNT / 10 ** BASE_DECIMALS} base tokens`); + }); + + it("fails when redeeming more than vault balance", async () => { + console.log("\n=== Test: Insufficient Balance Error ==="); + + // Try to redeem way more than vault has + const tooMuchBase = 10_000_000 * 10 ** BASE_DECIMALS; // 10M base = ~2758 quote needed + + try { + await program.methods + .redeem(new anchor.BN(tooMuchBase)) + .accounts({ + user: userKeypair.publicKey, + vault, + baseMint, + quoteMint, + vaultQuoteAta, + vaultBaseAta, + userBaseAta, + userQuoteAta, + baseTokenProgram: TOKEN_PROGRAM_ID, + quoteTokenProgram: TOKEN_PROGRAM_ID, + associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID, + systemProgram: SystemProgram.programId, + }) + .signers([userKeypair]) + .rpc(); + + expect.fail("Should have thrown InsufficientBalance error"); + } catch (err: any) { + expect(err.error?.errorCode?.code || err.message).to.include("InsufficientBalance"); + console.log("✓ Correctly rejected: InsufficientBalance"); + } + }); + + it("admin withdraws leftover quote", async () => { + console.log("\n=== Test: Admin Withdraw ==="); + + // Check vault quote balance + const vaultQuoteBefore = await provider.connection.getTokenAccountBalance(vaultQuoteAta); + const vaultBaseBefore = await provider.connection.getTokenAccountBalance(vaultBaseAta); + const quoteToWithdraw = Number(vaultQuoteBefore.value.amount); + const baseToWithdraw = Number(vaultBaseBefore.value.amount); + + console.log(`Vault quote balance: ${quoteToWithdraw / 10 ** QUOTE_DECIMALS}`); + console.log(`Vault base balance: ${baseToWithdraw / 10 ** BASE_DECIMALS}`); + + // Setup admin base ATA if needed + const adminBaseAccount = await getOrCreateAssociatedTokenAccount( + provider.connection, + admin.payer, + baseMint, + admin.publicKey + ); + adminBaseAta = adminBaseAccount.address; + + await program.methods + .withdraw(new anchor.BN(quoteToWithdraw), new anchor.BN(baseToWithdraw)) + .accounts({ + admin: admin.publicKey, + vault, + baseMint, + quoteMint, + vaultQuoteAta, + vaultBaseAta, + adminQuoteAta, + adminBaseAta, + baseTokenProgram: TOKEN_PROGRAM_ID, + quoteTokenProgram: TOKEN_PROGRAM_ID, + associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID, + systemProgram: SystemProgram.programId, + }) + .rpc(); + + // Verify vault is empty + const vaultQuoteAfter = await provider.connection.getTokenAccountBalance(vaultQuoteAta); + const vaultBaseAfter = await provider.connection.getTokenAccountBalance(vaultBaseAta); + + expect(Number(vaultQuoteAfter.value.amount)).to.equal(0); + expect(Number(vaultBaseAfter.value.amount)).to.equal(0); + + console.log(`✓ Admin withdrew ${quoteToWithdraw / 10 ** QUOTE_DECIMALS} quote tokens`); + console.log(`✓ Admin withdrew ${baseToWithdraw / 10 ** BASE_DECIMALS} base tokens`); + console.log("✓ Vault is now empty"); + }); + + after(() => { + console.log("\n=== Summary ==="); + console.log(`Vault: ${vault.toBase58()}`); + console.log(`Base Mint: ${baseMint.toBase58()}`); + console.log(`Quote Mint: ${quoteMint.toBase58()}`); + console.log("All tests passed ✓"); + }); +}); From 84f0e04347344534714de0c2ae7ef2cacbafc971 Mon Sep 17 00:00:00 2001 From: Alex Janiak Date: Tue, 17 Feb 2026 13:01:05 -0500 Subject: [PATCH 11/19] fix: round price down to 275 --- package-lock.json | 2931 +++++++++++++++++++++++++++++++ tests/redemption/devnet-test.ts | 4 +- yarn.lock | 922 +++++++--- 3 files changed, 3646 insertions(+), 211 deletions(-) create mode 100644 package-lock.json diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..371fc50 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2931 @@ +{ + "name": "programs", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "license": "ISC", + "dependencies": { + "@coral-xyz/anchor": "^0.32.1", + "@solana/spl-token": "^0.4.14", + "@solana/web3.js": "^1.98.4", + "@sqds/multisig": "^2.1.4" + }, + "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": "^5.7.3" + } + }, + "node_modules/@babel/runtime": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", + "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@coral-xyz/anchor": { + "version": "0.32.1", + "resolved": "https://registry.npmjs.org/@coral-xyz/anchor/-/anchor-0.32.1.tgz", + "integrity": "sha512-zAyxFtfeje2FbMA1wzgcdVs7Hng/MijPKpRijoySPCicnvcTQs/+dnPZ/cR+LcXM9v9UYSyW81uRNYZtN5G4yg==", + "license": "(MIT OR Apache-2.0)", + "dependencies": { + "@coral-xyz/anchor-errors": "^0.31.1", + "@coral-xyz/borsh": "^0.31.1", + "@noble/hashes": "^1.3.1", + "@solana/web3.js": "^1.69.0", + "bn.js": "^5.1.2", + "bs58": "^4.0.1", + "buffer-layout": "^1.2.2", + "camelcase": "^6.3.0", + "cross-fetch": "^3.1.5", + "eventemitter3": "^4.0.7", + "pako": "^2.0.3", + "superstruct": "^0.15.4", + "toml": "^3.0.0" + }, + "engines": { + "node": ">=17" + } + }, + "node_modules/@coral-xyz/anchor-errors": { + "version": "0.31.1", + "resolved": "https://registry.npmjs.org/@coral-xyz/anchor-errors/-/anchor-errors-0.31.1.tgz", + "integrity": "sha512-NhNEku4F3zzUSBtrYz84FzYWm48+9OvmT1Hhnwr6GnPQry2dsEqH/ti/7ASjjpoFTWRnPXrjAIT1qM6Isop+LQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=10" + } + }, + "node_modules/@coral-xyz/borsh": { + "version": "0.31.1", + "resolved": "https://registry.npmjs.org/@coral-xyz/borsh/-/borsh-0.31.1.tgz", + "integrity": "sha512-9N8AU9F0ubriKfNE3g1WF0/4dtlGXoBN/hd1PvbNBamBNwRgHxH4P+o3Zt7rSEloW1HUs6LfZEchlx9fW7POYw==", + "license": "Apache-2.0", + "dependencies": { + "bn.js": "^5.1.2", + "buffer-layout": "^1.2.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@solana/web3.js": "^1.69.0" + } + }, + "node_modules/@metaplex-foundation/beet": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@metaplex-foundation/beet/-/beet-0.7.1.tgz", + "integrity": "sha512-hNCEnS2WyCiYyko82rwuISsBY3KYpe828ubsd2ckeqZr7tl0WVLivGkoyA/qdiaaHEBGdGl71OpfWa2rqL3DiA==", + "license": "Apache-2.0", + "dependencies": { + "ansicolors": "^0.3.2", + "bn.js": "^5.2.0", + "debug": "^4.3.3" + } + }, + "node_modules/@metaplex-foundation/beet-solana": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@metaplex-foundation/beet-solana/-/beet-solana-0.4.0.tgz", + "integrity": "sha512-B1L94N3ZGMo53b0uOSoznbuM5GBNJ8LwSeznxBxJ+OThvfHQ4B5oMUqb+0zdLRfkKGS7Q6tpHK9P+QK0j3w2cQ==", + "license": "Apache-2.0", + "dependencies": { + "@metaplex-foundation/beet": ">=0.1.0", + "@solana/web3.js": "^1.56.2", + "bs58": "^5.0.0", + "debug": "^4.3.4" + } + }, + "node_modules/@metaplex-foundation/beet-solana/node_modules/base-x": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-4.0.1.tgz", + "integrity": "sha512-uAZ8x6r6S3aUM9rbHGVOIsR15U/ZSc82b3ymnCPsT45Gk1DDvhDPdIgB5MrhirZWt+5K0EEPQH985kNqZgNPFw==", + "license": "MIT" + }, + "node_modules/@metaplex-foundation/beet-solana/node_modules/bs58": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-5.0.0.tgz", + "integrity": "sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==", + "license": "MIT", + "dependencies": { + "base-x": "^4.0.0" + } + }, + "node_modules/@metaplex-foundation/cusper": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@metaplex-foundation/cusper/-/cusper-0.0.2.tgz", + "integrity": "sha512-S9RulC2fFCFOQraz61bij+5YCHhSO9llJegK8c8Y6731fSi6snUSQJdCUqYS8AIgR0TKbQvdvgSyIIdbDFZbBA==", + "license": "Apache-2.0" + }, + "node_modules/@noble/curves": { + "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz", + "integrity": "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.8.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@solana/buffer-layout": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@solana/buffer-layout/-/buffer-layout-4.0.1.tgz", + "integrity": "sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA==", + "license": "MIT", + "dependencies": { + "buffer": "~6.0.3" + }, + "engines": { + "node": ">=5.10" + } + }, + "node_modules/@solana/buffer-layout-utils": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@solana/buffer-layout-utils/-/buffer-layout-utils-0.2.0.tgz", + "integrity": "sha512-szG4sxgJGktbuZYDg2FfNmkMi0DYQoVjN2h7ta1W1hPrwzarcFLBq9UpX1UjNXsNpT9dn+chgprtWGioUAr4/g==", + "license": "Apache-2.0", + "dependencies": { + "@solana/buffer-layout": "^4.0.0", + "@solana/web3.js": "^1.32.0", + "bigint-buffer": "^1.1.5", + "bignumber.js": "^9.0.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@solana/codecs": { + "version": "2.0.0-rc.1", + "resolved": "https://registry.npmjs.org/@solana/codecs/-/codecs-2.0.0-rc.1.tgz", + "integrity": "sha512-qxoR7VybNJixV51L0G1RD2boZTcxmwUWnKCaJJExQ5qNKwbpSyDdWfFJfM5JhGyKe9DnPVOZB+JHWXnpbZBqrQ==", + "license": "MIT", + "dependencies": { + "@solana/codecs-core": "2.0.0-rc.1", + "@solana/codecs-data-structures": "2.0.0-rc.1", + "@solana/codecs-numbers": "2.0.0-rc.1", + "@solana/codecs-strings": "2.0.0-rc.1", + "@solana/options": "2.0.0-rc.1" + }, + "peerDependencies": { + "typescript": ">=5" + } + }, + "node_modules/@solana/codecs-core": { + "version": "2.0.0-rc.1", + "resolved": "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-2.0.0-rc.1.tgz", + "integrity": "sha512-bauxqMfSs8EHD0JKESaNmNuNvkvHSuN3bbWAF5RjOfDu2PugxHrvRebmYauvSumZ3cTfQ4HJJX6PG5rN852qyQ==", + "license": "MIT", + "dependencies": { + "@solana/errors": "2.0.0-rc.1" + }, + "peerDependencies": { + "typescript": ">=5" + } + }, + "node_modules/@solana/codecs-data-structures": { + "version": "2.0.0-rc.1", + "resolved": "https://registry.npmjs.org/@solana/codecs-data-structures/-/codecs-data-structures-2.0.0-rc.1.tgz", + "integrity": "sha512-rinCv0RrAVJ9rE/rmaibWJQxMwC5lSaORSZuwjopSUE6T0nb/MVg6Z1siNCXhh/HFTOg0l8bNvZHgBcN/yvXog==", + "license": "MIT", + "dependencies": { + "@solana/codecs-core": "2.0.0-rc.1", + "@solana/codecs-numbers": "2.0.0-rc.1", + "@solana/errors": "2.0.0-rc.1" + }, + "peerDependencies": { + "typescript": ">=5" + } + }, + "node_modules/@solana/codecs-numbers": { + "version": "2.0.0-rc.1", + "resolved": "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-2.0.0-rc.1.tgz", + "integrity": "sha512-J5i5mOkvukXn8E3Z7sGIPxsThRCgSdgTWJDQeZvucQ9PT6Y3HiVXJ0pcWiOWAoQ3RX8e/f4I3IC+wE6pZiJzDQ==", + "license": "MIT", + "dependencies": { + "@solana/codecs-core": "2.0.0-rc.1", + "@solana/errors": "2.0.0-rc.1" + }, + "peerDependencies": { + "typescript": ">=5" + } + }, + "node_modules/@solana/codecs-strings": { + "version": "2.0.0-rc.1", + "resolved": "https://registry.npmjs.org/@solana/codecs-strings/-/codecs-strings-2.0.0-rc.1.tgz", + "integrity": "sha512-9/wPhw8TbGRTt6mHC4Zz1RqOnuPTqq1Nb4EyuvpZ39GW6O2t2Q7Q0XxiB3+BdoEjwA2XgPw6e2iRfvYgqty44g==", + "license": "MIT", + "dependencies": { + "@solana/codecs-core": "2.0.0-rc.1", + "@solana/codecs-numbers": "2.0.0-rc.1", + "@solana/errors": "2.0.0-rc.1" + }, + "peerDependencies": { + "fastestsmallesttextencoderdecoder": "^1.0.22", + "typescript": ">=5" + } + }, + "node_modules/@solana/errors": { + "version": "2.0.0-rc.1", + "resolved": "https://registry.npmjs.org/@solana/errors/-/errors-2.0.0-rc.1.tgz", + "integrity": "sha512-ejNvQ2oJ7+bcFAYWj225lyRkHnixuAeb7RQCixm+5mH4n1IA4Qya/9Bmfy5RAAHQzxK43clu3kZmL5eF9VGtYQ==", + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "commander": "^12.1.0" + }, + "bin": { + "errors": "bin/cli.mjs" + }, + "peerDependencies": { + "typescript": ">=5" + } + }, + "node_modules/@solana/options": { + "version": "2.0.0-rc.1", + "resolved": "https://registry.npmjs.org/@solana/options/-/options-2.0.0-rc.1.tgz", + "integrity": "sha512-mLUcR9mZ3qfHlmMnREdIFPf9dpMc/Bl66tLSOOWxw4ml5xMT2ohFn7WGqoKcu/UHkT9CrC6+amEdqCNvUqI7AA==", + "license": "MIT", + "dependencies": { + "@solana/codecs-core": "2.0.0-rc.1", + "@solana/codecs-data-structures": "2.0.0-rc.1", + "@solana/codecs-numbers": "2.0.0-rc.1", + "@solana/codecs-strings": "2.0.0-rc.1", + "@solana/errors": "2.0.0-rc.1" + }, + "peerDependencies": { + "typescript": ">=5" + } + }, + "node_modules/@solana/spl-token": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/@solana/spl-token/-/spl-token-0.4.14.tgz", + "integrity": "sha512-u09zr96UBpX4U685MnvQsNzlvw9TiY005hk1vJmJr7gMJldoPG1eYU5/wNEyOA5lkMLiR/gOi9SFD4MefOYEsA==", + "license": "Apache-2.0", + "dependencies": { + "@solana/buffer-layout": "^4.0.0", + "@solana/buffer-layout-utils": "^0.2.0", + "@solana/spl-token-group": "^0.0.7", + "@solana/spl-token-metadata": "^0.1.6", + "buffer": "^6.0.3" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "@solana/web3.js": "^1.95.5" + } + }, + "node_modules/@solana/spl-token-group": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/@solana/spl-token-group/-/spl-token-group-0.0.7.tgz", + "integrity": "sha512-V1N/iX7Cr7H0uazWUT2uk27TMqlqedpXHRqqAbVO2gvmJyT0E0ummMEAVQeXZ05ZhQ/xF39DLSdBp90XebWEug==", + "license": "Apache-2.0", + "dependencies": { + "@solana/codecs": "2.0.0-rc.1" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "@solana/web3.js": "^1.95.3" + } + }, + "node_modules/@solana/spl-token-metadata": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@solana/spl-token-metadata/-/spl-token-metadata-0.1.6.tgz", + "integrity": "sha512-7sMt1rsm/zQOQcUWllQX9mD2O6KhSAtY1hFR2hfFwgqfFWzSY9E9GDvFVNYUI1F0iQKcm6HmePU9QbKRXTEBiA==", + "license": "Apache-2.0", + "dependencies": { + "@solana/codecs": "2.0.0-rc.1" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "@solana/web3.js": "^1.95.3" + } + }, + "node_modules/@solana/web3.js": { + "version": "1.98.4", + "resolved": "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.98.4.tgz", + "integrity": "sha512-vv9lfnvjUsRiq//+j5pBdXig0IQdtzA0BRZ3bXEP4KaIyF1CcaydWqgyzQgfZMNIsWNWmG+AUHwPy4AHOD6gpw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.25.0", + "@noble/curves": "^1.4.2", + "@noble/hashes": "^1.4.0", + "@solana/buffer-layout": "^4.0.1", + "@solana/codecs-numbers": "^2.1.0", + "agentkeepalive": "^4.5.0", + "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" + } + }, + "node_modules/@solana/web3.js/node_modules/@solana/codecs-core": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-2.3.0.tgz", + "integrity": "sha512-oG+VZzN6YhBHIoSKgS5ESM9VIGzhWjEHEGNPSibiDTxFhsFWxNaz8LbMDPjBUE69r9wmdGLkrQ+wVPbnJcZPvw==", + "license": "MIT", + "dependencies": { + "@solana/errors": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/web3.js/node_modules/@solana/codecs-numbers": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-2.3.0.tgz", + "integrity": "sha512-jFvvwKJKffvG7Iz9dmN51OGB7JBcy2CJ6Xf3NqD/VP90xak66m/Lg48T01u5IQ/hc15mChVHiBm+HHuOFDUrQg==", + "license": "MIT", + "dependencies": { + "@solana/codecs-core": "2.3.0", + "@solana/errors": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/web3.js/node_modules/@solana/errors": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/errors/-/errors-2.3.0.tgz", + "integrity": "sha512-66RI9MAbwYV0UtP7kGcTBVLxJgUxoZGm8Fbc0ah+lGiAw17Gugco6+9GrJCV83VyF2mDWyYnYM9qdI3yjgpnaQ==", + "license": "MIT", + "dependencies": { + "chalk": "^5.4.1", + "commander": "^14.0.0" + }, + "bin": { + "errors": "bin/cli.mjs" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/web3.js/node_modules/commander": { + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz", + "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==", + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/@solana/web3.js/node_modules/superstruct": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-2.0.2.tgz", + "integrity": "sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@sqds/multisig": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@sqds/multisig/-/multisig-2.1.4.tgz", + "integrity": "sha512-5w+NmwHOzl96nI50R/fjSD6uFydRLNUquhoEmmWbGepS4D9DnQyF2TKcUBfTyxV3sgJt00ypBt7SXB3y8WOzUQ==", + "license": "MIT", + "dependencies": { + "@metaplex-foundation/beet": "0.7.1", + "@metaplex-foundation/beet-solana": "0.4.0", + "@metaplex-foundation/cusper": "^0.0.2", + "@solana/spl-token": "^0.3.6", + "@solana/web3.js": "^1.70.3", + "@types/bn.js": "^5.1.1", + "assert": "^2.0.0", + "bn.js": "^5.2.1", + "buffer": "6.0.3", + "invariant": "2.2.4" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@sqds/multisig/node_modules/@solana/spl-token": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@solana/spl-token/-/spl-token-0.3.11.tgz", + "integrity": "sha512-bvohO3rIMSVL24Pb+I4EYTJ6cL82eFpInEXD/I8K8upOGjpqHsKUoAempR/RnUlI1qSFNyFlWJfu6MNUgfbCQQ==", + "license": "Apache-2.0", + "dependencies": { + "@solana/buffer-layout": "^4.0.0", + "@solana/buffer-layout-utils": "^0.2.0", + "@solana/spl-token-metadata": "^0.1.2", + "buffer": "^6.0.3" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "@solana/web3.js": "^1.88.0" + } + }, + "node_modules/@swc/helpers": { + "version": "0.5.17", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz", + "integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@types/bn.js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.2.0.tgz", + "integrity": "sha512-DLbJ1BPqxvQhIGbeu8VbUC1DiAiahHtAYvA0ZEAa4P31F7IaArc8z3C3BRQdWX4mtLQuABG4yzp76ZrS02Ui1Q==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/chai": { + "version": "4.3.20", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.20.tgz", + "integrity": "sha512-/pC9HAB5I/xMlc5FP77qjCnI16ChlJfW0tGa0IUcFn38VJrTV6DeZ60NU5KZBtaOZqjdpwTWohz5HU1RrhiYxQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/@types/mocha": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.1.tgz", + "integrity": "sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "24.10.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz", + "integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/@types/uuid": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", + "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==", + "license": "MIT" + }, + "node_modules/@types/ws": { + "version": "7.4.7", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", + "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@ungap/promise-all-settled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", + "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "dev": true, + "license": "ISC" + }, + "node_modules/agentkeepalive": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", + "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", + "license": "MIT", + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ansicolors": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz", + "integrity": "sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg==", + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/assert": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-2.1.0.tgz", + "integrity": "sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "is-nan": "^1.3.2", + "object-is": "^1.1.5", + "object.assign": "^4.1.4", + "util": "^0.12.5" + } + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/base-x": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.11.tgz", + "integrity": "sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bigint-buffer": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/bigint-buffer/-/bigint-buffer-1.1.5.tgz", + "integrity": "sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "bindings": "^1.3.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/bignumber.js": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", + "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "license": "MIT", + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/bn.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.2.tgz", + "integrity": "sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==", + "license": "MIT" + }, + "node_modules/borsh": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/borsh/-/borsh-0.7.0.tgz", + "integrity": "sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==", + "license": "Apache-2.0", + "dependencies": { + "bn.js": "^5.2.0", + "bs58": "^4.0.0", + "text-encoding-utf-8": "^1.0.2" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true, + "license": "ISC" + }, + "node_modules/bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "license": "MIT", + "dependencies": { + "base-x": "^3.0.2" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/buffer-layout": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/buffer-layout/-/buffer-layout-1.2.2.tgz", + "integrity": "sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA==", + "license": "MIT", + "engines": { + "node": ">=4.5" + } + }, + "node_modules/bufferutil": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.9.tgz", + "integrity": "sha512-WDtdLmJvAuNNPzByAYpRo2rF1Mmradw6gvWsQKf63476DDXmomT9zUiGypLcG4ibIM67vhAj8jJRdbmEws2Aqw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chai": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz", + "integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/check-error": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-func-name": "^2.0.2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-fetch": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.2.0.tgz", + "integrity": "sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==", + "license": "MIT", + "dependencies": { + "node-fetch": "^2.7.0" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-eql": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", + "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delay": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz", + "integrity": "sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "license": "MIT" + }, + "node_modules/es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", + "license": "MIT", + "dependencies": { + "es6-promise": "^4.0.3" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "license": "MIT" + }, + "node_modules/eyes": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", + "integrity": "sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==", + "engines": { + "node": "> 0.1.90" + } + }, + "node_modules/fast-stable-stringify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-stable-stringify/-/fast-stable-stringify-1.0.0.tgz", + "integrity": "sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag==", + "license": "MIT" + }, + "node_modules/fastestsmallesttextencoderdecoder": { + "version": "1.0.22", + "resolved": "https://registry.npmjs.org/fastestsmallesttextencoderdecoder/-/fastestsmallesttextencoderdecoder-1.0.22.tgz", + "integrity": "sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw==", + "license": "CC0-1.0", + "peer": true + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "license": "MIT" + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-func-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.x" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/is-arguments": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", + "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-nan": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", + "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/isomorphic-ws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", + "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", + "license": "MIT", + "peerDependencies": { + "ws": "*" + } + }, + "node_modules/jayson": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/jayson/-/jayson-4.2.0.tgz", + "integrity": "sha512-VfJ9t1YLwacIubLhONk0KFeosUBwstRWQ0IRT1KDjEjnVnSOVHC3uwugyV7L0c7R9lpVyrUGT2XWiBA1UTtpyg==", + "license": "MIT", + "dependencies": { + "@types/connect": "^3.4.33", + "@types/node": "^12.12.54", + "@types/ws": "^7.4.4", + "commander": "^2.20.3", + "delay": "^5.0.0", + "es6-promisify": "^5.0.0", + "eyes": "^0.1.8", + "isomorphic-ws": "^4.0.1", + "json-stringify-safe": "^5.0.1", + "stream-json": "^1.9.1", + "uuid": "^8.3.2", + "ws": "^7.5.10" + }, + "bin": { + "jayson": "bin/jayson.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jayson/node_modules/@types/node": { + "version": "12.20.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", + "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", + "license": "MIT" + }, + "node_modules/jayson/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "license": "ISC" + }, + "node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/loupe": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-func-name": "^2.0.1" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/minimatch": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz", + "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mocha": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz", + "integrity": "sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==", + "dev": true, + "license": "MIT", + "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" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/mocha/node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/mocha/node_modules/debug/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", + "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", + "dev": true, + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-gyp-build": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", + "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", + "license": "MIT", + "optional": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-is": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", + "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pako": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", + "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==", + "license": "(MIT AND Zlib)" + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rpc-websockets": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/rpc-websockets/-/rpc-websockets-9.3.1.tgz", + "integrity": "sha512-bY6a+i/lEtBJ/mUxwsCTgevoV1P0foXTVA7UoThzaIWbM+3NDqorf8NBWs5DmqKTFeA1IoNzgvkWjFCPgnzUiQ==", + "license": "LGPL-3.0-only", + "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" + }, + "funding": { + "type": "paypal", + "url": "https://paypal.me/kozjak" + }, + "optionalDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + } + }, + "node_modules/rpc-websockets/node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/rpc-websockets/node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "license": "MIT" + }, + "node_modules/rpc-websockets/node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/stream-chain": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/stream-chain/-/stream-chain-2.2.5.tgz", + "integrity": "sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA==", + "license": "BSD-3-Clause" + }, + "node_modules/stream-json": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/stream-json/-/stream-json-1.9.1.tgz", + "integrity": "sha512-uWkjJ+2Nt/LO9Z/JyKZbMusL8Dkh97uUBTv3AJQ74y07lVahLY4eEFsPsE97pxYBwr8nnjMAIch5eqI0gPShyw==", + "license": "BSD-3-Clause", + "dependencies": { + "stream-chain": "^2.2.5" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/superstruct": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-0.15.5.tgz", + "integrity": "sha512-4AOeU+P5UuE/4nOUkmcQdW5y7i9ndt1cQd/3iUe+LTz3RxESf/W/5lg4B74HbDMMv8PHnPnGCQFH45kBcrQYoQ==", + "license": "MIT" + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/text-encoding-utf-8": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz", + "integrity": "sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toml": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz", + "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==", + "license": "MIT" + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/ts-mocha": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/ts-mocha/-/ts-mocha-10.1.0.tgz", + "integrity": "sha512-T0C0Xm3/WqCuF2tpa0GNGESTBoKZaiqdUP8guNv4ZY316AFXlyidnrzQ1LUrCT0Wb1i3J0zFTgOh/55Un44WdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ts-node": "7.0.1" + }, + "bin": { + "ts-mocha": "bin/ts-mocha" + }, + "engines": { + "node": ">= 6.X.X" + }, + "optionalDependencies": { + "tsconfig-paths": "^3.5.0" + }, + "peerDependencies": { + "mocha": "^3.X.X || ^4.X.X || ^5.X.X || ^6.X.X || ^7.X.X || ^8.X.X || ^9.X.X || ^10.X.X || ^11.X.X" + } + }, + "node_modules/ts-node": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz", + "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "arrify": "^1.0.0", + "buffer-from": "^1.1.0", + "diff": "^3.1.0", + "make-error": "^1.1.1", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "source-map-support": "^0.5.6", + "yn": "^2.0.0" + }, + "bin": { + "ts-node": "dist/bin.js" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/ts-node/node_modules/diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/type-detect": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "license": "MIT" + }, + "node_modules/utf-8-validate": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", + "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.20", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz", + "integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==", + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/workerpool": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", + "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", + "integrity": "sha512-uTv8J/wiWTgUTg+9vLTi//leUl5vDQS6uii/emeTb2ssY7vl6QWf2fFbIIGjnhjvbdKlU0ed7QPgY1htTC86jQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/tests/redemption/devnet-test.ts b/tests/redemption/devnet-test.ts index b2cac07..8626ae4 100644 --- a/tests/redemption/devnet-test.ts +++ b/tests/redemption/devnet-test.ts @@ -34,8 +34,8 @@ const VAULT_SEED = Buffer.from("redemption"); // Test parameters const BASE_DECIMALS = 9; const QUOTE_DECIMALS = 6; -const UI_PRICE = 0.0002758; // 0.0002758 quote per base -const PRICE = Math.round(UI_PRICE * 10 ** QUOTE_DECIMALS); // 276 +const UI_PRICE = 0.000275; // ~0.0002758 quote per base (rounded down) +const PRICE = Math.floor(UI_PRICE * 10 ** QUOTE_DECIMALS); // 275 const UI_REDEEM_AMOUNT = 1_000_000; // 1 million base tokens const RAW_REDEEM_AMOUNT = UI_REDEEM_AMOUNT * 10 ** BASE_DECIMALS; diff --git a/yarn.lock b/yarn.lock index 592b006..f55ee81 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4,17 +4,17 @@ "@babel/runtime@^7.25.0": version "7.28.4" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.28.4.tgz#a70226016fabe25c5783b2f22d3e1c9bc5ca3326" + resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz" integrity sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ== "@coral-xyz/anchor-errors@^0.31.1": version "0.31.1" - resolved "https://registry.yarnpkg.com/@coral-xyz/anchor-errors/-/anchor-errors-0.31.1.tgz#d635cbac2533973ae6bfb5d3ba1de89ce5aece2d" + resolved "https://registry.npmjs.org/@coral-xyz/anchor-errors/-/anchor-errors-0.31.1.tgz" integrity sha512-NhNEku4F3zzUSBtrYz84FzYWm48+9OvmT1Hhnwr6GnPQry2dsEqH/ti/7ASjjpoFTWRnPXrjAIT1qM6Isop+LQ== "@coral-xyz/anchor@^0.32.1": version "0.32.1" - resolved "https://registry.yarnpkg.com/@coral-xyz/anchor/-/anchor-0.32.1.tgz#a07440d9d267840f4f99f1493bd8ce7d7f128e57" + resolved "https://registry.npmjs.org/@coral-xyz/anchor/-/anchor-0.32.1.tgz" integrity sha512-zAyxFtfeje2FbMA1wzgcdVs7Hng/MijPKpRijoySPCicnvcTQs/+dnPZ/cR+LcXM9v9UYSyW81uRNYZtN5G4yg== dependencies: "@coral-xyz/anchor-errors" "^0.31.1" @@ -33,57 +33,189 @@ "@coral-xyz/borsh@^0.31.1": version "0.31.1" - resolved "https://registry.yarnpkg.com/@coral-xyz/borsh/-/borsh-0.31.1.tgz#5328e1e0921b75d7f4a62dd3f61885a938bc7241" + resolved "https://registry.npmjs.org/@coral-xyz/borsh/-/borsh-0.31.1.tgz" integrity sha512-9N8AU9F0ubriKfNE3g1WF0/4dtlGXoBN/hd1PvbNBamBNwRgHxH4P+o3Zt7rSEloW1HUs6LfZEchlx9fW7POYw== dependencies: bn.js "^5.1.2" buffer-layout "^1.2.0" +"@metaplex-foundation/beet-solana@0.4.0": + version "0.4.0" + resolved "https://registry.npmjs.org/@metaplex-foundation/beet-solana/-/beet-solana-0.4.0.tgz" + integrity sha512-B1L94N3ZGMo53b0uOSoznbuM5GBNJ8LwSeznxBxJ+OThvfHQ4B5oMUqb+0zdLRfkKGS7Q6tpHK9P+QK0j3w2cQ== + dependencies: + "@metaplex-foundation/beet" ">=0.1.0" + "@solana/web3.js" "^1.56.2" + bs58 "^5.0.0" + debug "^4.3.4" + +"@metaplex-foundation/beet@>=0.1.0", "@metaplex-foundation/beet@0.7.1": + version "0.7.1" + resolved "https://registry.npmjs.org/@metaplex-foundation/beet/-/beet-0.7.1.tgz" + integrity sha512-hNCEnS2WyCiYyko82rwuISsBY3KYpe828ubsd2ckeqZr7tl0WVLivGkoyA/qdiaaHEBGdGl71OpfWa2rqL3DiA== + dependencies: + ansicolors "^0.3.2" + bn.js "^5.2.0" + debug "^4.3.3" + +"@metaplex-foundation/cusper@^0.0.2": + version "0.0.2" + resolved "https://registry.npmjs.org/@metaplex-foundation/cusper/-/cusper-0.0.2.tgz" + integrity sha512-S9RulC2fFCFOQraz61bij+5YCHhSO9llJegK8c8Y6731fSi6snUSQJdCUqYS8AIgR0TKbQvdvgSyIIdbDFZbBA== + "@noble/curves@^1.4.2": version "1.9.7" - resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.9.7.tgz#79d04b4758a43e4bca2cbdc62e7771352fa6b951" + resolved "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz" integrity sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw== dependencies: "@noble/hashes" "1.8.0" -"@noble/hashes@1.8.0", "@noble/hashes@^1.3.1", "@noble/hashes@^1.4.0": +"@noble/hashes@^1.3.1", "@noble/hashes@^1.4.0", "@noble/hashes@1.8.0": version "1.8.0" - resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.8.0.tgz#cee43d801fcef9644b11b8194857695acd5f815a" + resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz" integrity sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A== -"@solana/buffer-layout@^4.0.1": +"@solana/buffer-layout-utils@^0.2.0": + version "0.2.0" + resolved "https://registry.npmjs.org/@solana/buffer-layout-utils/-/buffer-layout-utils-0.2.0.tgz" + integrity sha512-szG4sxgJGktbuZYDg2FfNmkMi0DYQoVjN2h7ta1W1hPrwzarcFLBq9UpX1UjNXsNpT9dn+chgprtWGioUAr4/g== + dependencies: + "@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.1": version "4.0.1" - resolved "https://registry.yarnpkg.com/@solana/buffer-layout/-/buffer-layout-4.0.1.tgz#b996235eaec15b1e0b5092a8ed6028df77fa6c15" + resolved "https://registry.npmjs.org/@solana/buffer-layout/-/buffer-layout-4.0.1.tgz" integrity sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA== dependencies: buffer "~6.0.3" +"@solana/codecs-core@2.0.0-rc.1": + version "2.0.0-rc.1" + resolved "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-2.0.0-rc.1.tgz" + integrity sha512-bauxqMfSs8EHD0JKESaNmNuNvkvHSuN3bbWAF5RjOfDu2PugxHrvRebmYauvSumZ3cTfQ4HJJX6PG5rN852qyQ== + dependencies: + "@solana/errors" "2.0.0-rc.1" + "@solana/codecs-core@2.3.0": version "2.3.0" - resolved "https://registry.yarnpkg.com/@solana/codecs-core/-/codecs-core-2.3.0.tgz#6bf2bb565cb1ae880f8018635c92f751465d8695" + resolved "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-2.3.0.tgz" integrity sha512-oG+VZzN6YhBHIoSKgS5ESM9VIGzhWjEHEGNPSibiDTxFhsFWxNaz8LbMDPjBUE69r9wmdGLkrQ+wVPbnJcZPvw== dependencies: "@solana/errors" "2.3.0" +"@solana/codecs-data-structures@2.0.0-rc.1": + version "2.0.0-rc.1" + resolved "https://registry.npmjs.org/@solana/codecs-data-structures/-/codecs-data-structures-2.0.0-rc.1.tgz" + integrity sha512-rinCv0RrAVJ9rE/rmaibWJQxMwC5lSaORSZuwjopSUE6T0nb/MVg6Z1siNCXhh/HFTOg0l8bNvZHgBcN/yvXog== + dependencies: + "@solana/codecs-core" "2.0.0-rc.1" + "@solana/codecs-numbers" "2.0.0-rc.1" + "@solana/errors" "2.0.0-rc.1" + "@solana/codecs-numbers@^2.1.0": version "2.3.0" - resolved "https://registry.yarnpkg.com/@solana/codecs-numbers/-/codecs-numbers-2.3.0.tgz#ac7e7f38aaf7fcd22ce2061fbdcd625e73828dc6" + resolved "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-2.3.0.tgz" integrity sha512-jFvvwKJKffvG7Iz9dmN51OGB7JBcy2CJ6Xf3NqD/VP90xak66m/Lg48T01u5IQ/hc15mChVHiBm+HHuOFDUrQg== dependencies: "@solana/codecs-core" "2.3.0" "@solana/errors" "2.3.0" +"@solana/codecs-numbers@2.0.0-rc.1": + version "2.0.0-rc.1" + resolved "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-2.0.0-rc.1.tgz" + integrity sha512-J5i5mOkvukXn8E3Z7sGIPxsThRCgSdgTWJDQeZvucQ9PT6Y3HiVXJ0pcWiOWAoQ3RX8e/f4I3IC+wE6pZiJzDQ== + dependencies: + "@solana/codecs-core" "2.0.0-rc.1" + "@solana/errors" "2.0.0-rc.1" + +"@solana/codecs-strings@2.0.0-rc.1": + version "2.0.0-rc.1" + resolved "https://registry.npmjs.org/@solana/codecs-strings/-/codecs-strings-2.0.0-rc.1.tgz" + integrity sha512-9/wPhw8TbGRTt6mHC4Zz1RqOnuPTqq1Nb4EyuvpZ39GW6O2t2Q7Q0XxiB3+BdoEjwA2XgPw6e2iRfvYgqty44g== + dependencies: + "@solana/codecs-core" "2.0.0-rc.1" + "@solana/codecs-numbers" "2.0.0-rc.1" + "@solana/errors" "2.0.0-rc.1" + +"@solana/codecs@2.0.0-rc.1": + version "2.0.0-rc.1" + resolved "https://registry.npmjs.org/@solana/codecs/-/codecs-2.0.0-rc.1.tgz" + integrity sha512-qxoR7VybNJixV51L0G1RD2boZTcxmwUWnKCaJJExQ5qNKwbpSyDdWfFJfM5JhGyKe9DnPVOZB+JHWXnpbZBqrQ== + dependencies: + "@solana/codecs-core" "2.0.0-rc.1" + "@solana/codecs-data-structures" "2.0.0-rc.1" + "@solana/codecs-numbers" "2.0.0-rc.1" + "@solana/codecs-strings" "2.0.0-rc.1" + "@solana/options" "2.0.0-rc.1" + +"@solana/errors@2.0.0-rc.1": + version "2.0.0-rc.1" + resolved "https://registry.npmjs.org/@solana/errors/-/errors-2.0.0-rc.1.tgz" + integrity sha512-ejNvQ2oJ7+bcFAYWj225lyRkHnixuAeb7RQCixm+5mH4n1IA4Qya/9Bmfy5RAAHQzxK43clu3kZmL5eF9VGtYQ== + dependencies: + chalk "^5.3.0" + commander "^12.1.0" + "@solana/errors@2.3.0": version "2.3.0" - resolved "https://registry.yarnpkg.com/@solana/errors/-/errors-2.3.0.tgz#4ac9380343dbeffb9dffbcb77c28d0e457c5fa31" + resolved "https://registry.npmjs.org/@solana/errors/-/errors-2.3.0.tgz" integrity sha512-66RI9MAbwYV0UtP7kGcTBVLxJgUxoZGm8Fbc0ah+lGiAw17Gugco6+9GrJCV83VyF2mDWyYnYM9qdI3yjgpnaQ== dependencies: chalk "^5.4.1" commander "^14.0.0" -"@solana/web3.js@^1.69.0": +"@solana/options@2.0.0-rc.1": + version "2.0.0-rc.1" + resolved "https://registry.npmjs.org/@solana/options/-/options-2.0.0-rc.1.tgz" + integrity sha512-mLUcR9mZ3qfHlmMnREdIFPf9dpMc/Bl66tLSOOWxw4ml5xMT2ohFn7WGqoKcu/UHkT9CrC6+amEdqCNvUqI7AA== + dependencies: + "@solana/codecs-core" "2.0.0-rc.1" + "@solana/codecs-data-structures" "2.0.0-rc.1" + "@solana/codecs-numbers" "2.0.0-rc.1" + "@solana/codecs-strings" "2.0.0-rc.1" + "@solana/errors" "2.0.0-rc.1" + +"@solana/spl-token-group@^0.0.7": + version "0.0.7" + resolved "https://registry.npmjs.org/@solana/spl-token-group/-/spl-token-group-0.0.7.tgz" + integrity sha512-V1N/iX7Cr7H0uazWUT2uk27TMqlqedpXHRqqAbVO2gvmJyT0E0ummMEAVQeXZ05ZhQ/xF39DLSdBp90XebWEug== + dependencies: + "@solana/codecs" "2.0.0-rc.1" + +"@solana/spl-token-metadata@^0.1.2", "@solana/spl-token-metadata@^0.1.6": + version "0.1.6" + resolved "https://registry.npmjs.org/@solana/spl-token-metadata/-/spl-token-metadata-0.1.6.tgz" + integrity sha512-7sMt1rsm/zQOQcUWllQX9mD2O6KhSAtY1hFR2hfFwgqfFWzSY9E9GDvFVNYUI1F0iQKcm6HmePU9QbKRXTEBiA== + dependencies: + "@solana/codecs" "2.0.0-rc.1" + +"@solana/spl-token@^0.3.6": + version "0.3.11" + resolved "https://registry.npmjs.org/@solana/spl-token/-/spl-token-0.3.11.tgz" + integrity sha512-bvohO3rIMSVL24Pb+I4EYTJ6cL82eFpInEXD/I8K8upOGjpqHsKUoAempR/RnUlI1qSFNyFlWJfu6MNUgfbCQQ== + dependencies: + "@solana/buffer-layout" "^4.0.0" + "@solana/buffer-layout-utils" "^0.2.0" + "@solana/spl-token-metadata" "^0.1.2" + buffer "^6.0.3" + +"@solana/spl-token@^0.4.14": + version "0.4.14" + resolved "https://registry.npmjs.org/@solana/spl-token/-/spl-token-0.4.14.tgz" + integrity sha512-u09zr96UBpX4U685MnvQsNzlvw9TiY005hk1vJmJr7gMJldoPG1eYU5/wNEyOA5lkMLiR/gOi9SFD4MefOYEsA== + dependencies: + "@solana/buffer-layout" "^4.0.0" + "@solana/buffer-layout-utils" "^0.2.0" + "@solana/spl-token-group" "^0.0.7" + "@solana/spl-token-metadata" "^0.1.6" + buffer "^6.0.3" + +"@solana/web3.js@^1.32.0", "@solana/web3.js@^1.56.2", "@solana/web3.js@^1.69.0", "@solana/web3.js@^1.70.3", "@solana/web3.js@^1.88.0", "@solana/web3.js@^1.95.3", "@solana/web3.js@^1.95.5", "@solana/web3.js@^1.98.4": version "1.98.4" - resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.98.4.tgz#df51d78be9d865181ec5138b4e699d48e6895bbe" + resolved "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.98.4.tgz" integrity sha512-vv9lfnvjUsRiq//+j5pBdXig0IQdtzA0BRZ3bXEP4KaIyF1CcaydWqgyzQgfZMNIsWNWmG+AUHwPy4AHOD6gpw== dependencies: "@babel/runtime" "^7.25.0" @@ -102,105 +234,126 @@ rpc-websockets "^9.0.2" superstruct "^2.0.2" +"@sqds/multisig@^2.1.4": + version "2.1.4" + resolved "https://registry.npmjs.org/@sqds/multisig/-/multisig-2.1.4.tgz" + integrity sha512-5w+NmwHOzl96nI50R/fjSD6uFydRLNUquhoEmmWbGepS4D9DnQyF2TKcUBfTyxV3sgJt00ypBt7SXB3y8WOzUQ== + dependencies: + "@metaplex-foundation/beet" "0.7.1" + "@metaplex-foundation/beet-solana" "0.4.0" + "@metaplex-foundation/cusper" "^0.0.2" + "@solana/spl-token" "^0.3.6" + "@solana/web3.js" "^1.70.3" + "@types/bn.js" "^5.1.1" + assert "^2.0.0" + bn.js "^5.2.1" + buffer "6.0.3" + invariant "2.2.4" + "@swc/helpers@^0.5.11": version "0.5.17" - resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.17.tgz#5a7be95ac0f0bf186e7e6e890e7a6f6cda6ce971" + resolved "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz" integrity sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A== dependencies: tslib "^2.8.0" -"@types/bn.js@^5.1.0": +"@types/bn.js@^5.1.0", "@types/bn.js@^5.1.1": version "5.2.0" - resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.2.0.tgz#4349b9710e98f9ab3cdc50f1c5e4dcbd8ef29c80" + resolved "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.2.0.tgz" integrity sha512-DLbJ1BPqxvQhIGbeu8VbUC1DiAiahHtAYvA0ZEAa4P31F7IaArc8z3C3BRQdWX4mtLQuABG4yzp76ZrS02Ui1Q== dependencies: "@types/node" "*" "@types/chai@^4.3.0": version "4.3.20" - resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.20.tgz#cb291577ed342ca92600430841a00329ba05cecc" + resolved "https://registry.npmjs.org/@types/chai/-/chai-4.3.20.tgz" integrity sha512-/pC9HAB5I/xMlc5FP77qjCnI16ChlJfW0tGa0IUcFn38VJrTV6DeZ60NU5KZBtaOZqjdpwTWohz5HU1RrhiYxQ== "@types/connect@^3.4.33": version "3.4.38" - resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.38.tgz#5ba7f3bc4fbbdeaff8dded952e5ff2cc53f8d858" + resolved "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz" integrity sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug== dependencies: "@types/node" "*" "@types/json5@^0.0.29": version "0.0.29" - resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" + resolved "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz" integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== "@types/mocha@^9.0.0": version "9.1.1" - resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-9.1.1.tgz#e7c4f1001eefa4b8afbd1eee27a237fee3bf29c4" + resolved "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.1.tgz" integrity sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw== "@types/node@*": version "24.10.1" - resolved "https://registry.yarnpkg.com/@types/node/-/node-24.10.1.tgz#91e92182c93db8bd6224fca031e2370cef9a8f01" + resolved "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz" integrity sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ== dependencies: undici-types "~7.16.0" "@types/node@^12.12.54": version "12.20.55" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240" + resolved "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz" 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" + resolved "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz" 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" + resolved "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz" integrity sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww== dependencies: "@types/node" "*" "@types/ws@^8.2.2": version "8.18.1" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.18.1.tgz#48464e4bf2ddfd17db13d845467f6070ffea4aa9" + resolved "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz" integrity sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg== 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" + resolved "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz" integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== agentkeepalive@^4.5.0: version "4.6.0" - resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.6.0.tgz#35f73e94b3f40bf65f105219c623ad19c136ea6a" + resolved "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz" integrity sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ== dependencies: humanize-ms "^1.2.1" ansi-colors@4.1.1: version "4.1.1" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" + resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz" integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== ansi-regex@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== ansi-styles@^4.0.0, ansi-styles@^4.1.0: version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== dependencies: color-convert "^2.0.1" +ansicolors@^0.3.2: + version "0.3.2" + resolved "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz" + integrity sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg== + anymatch@~3.1.2: version "3.1.3" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz" integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== dependencies: normalize-path "^3.0.0" @@ -208,49 +361,91 @@ anymatch@~3.1.2: argparse@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== arrify@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + resolved "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz" integrity sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA== +assert@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/assert/-/assert-2.1.0.tgz" + integrity sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw== + dependencies: + call-bind "^1.0.2" + is-nan "^1.3.2" + object-is "^1.1.5" + object.assign "^4.1.4" + util "^0.12.5" + assertion-error@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" + resolved "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz" integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== +available-typed-arrays@^1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz" + integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== + dependencies: + possible-typed-array-names "^1.0.0" + balanced-match@^1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== base-x@^3.0.2: version "3.0.11" - resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.11.tgz#40d80e2a1aeacba29792ccc6c5354806421287ff" + resolved "https://registry.npmjs.org/base-x/-/base-x-3.0.11.tgz" integrity sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA== dependencies: safe-buffer "^5.0.1" +base-x@^4.0.0: + version "4.0.1" + resolved "https://registry.npmjs.org/base-x/-/base-x-4.0.1.tgz" + integrity sha512-uAZ8x6r6S3aUM9rbHGVOIsR15U/ZSc82b3ymnCPsT45Gk1DDvhDPdIgB5MrhirZWt+5K0EEPQH985kNqZgNPFw== + base64-js@^1.3.1: version "1.5.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== +bigint-buffer@^1.1.5: + version "1.1.5" + resolved "https://registry.npmjs.org/bigint-buffer/-/bigint-buffer-1.1.5.tgz" + integrity sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA== + dependencies: + bindings "^1.3.0" + +bignumber.js@^9.0.1: + version "9.3.1" + resolved "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz" + integrity sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ== + binary-extensions@^2.0.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" + resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz" integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== +bindings@^1.3.0: + version "1.5.0" + resolved "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== + dependencies: + file-uri-to-path "1.0.0" + bn.js@^5.1.2, bn.js@^5.2.0, bn.js@^5.2.1: version "5.2.2" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.2.tgz#82c09f9ebbb17107cd72cb7fd39bd1f9d0aaa566" + resolved "https://registry.npmjs.org/bn.js/-/bn.js-5.2.2.tgz" integrity sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw== borsh@^0.7.0: version "0.7.0" - resolved "https://registry.yarnpkg.com/borsh/-/borsh-0.7.0.tgz#6e9560d719d86d90dc589bca60ffc8a6c51fec2a" + resolved "https://registry.npmjs.org/borsh/-/borsh-0.7.0.tgz" integrity sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA== dependencies: bn.js "^5.2.0" @@ -259,7 +454,7 @@ borsh@^0.7.0: brace-expansion@^1.1.7: version "1.1.12" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.12.tgz#ab9b454466e5a8cc3a187beaad580412a9c5b843" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz" integrity sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg== dependencies: balanced-match "^1.0.0" @@ -267,36 +462,43 @@ brace-expansion@^1.1.7: braces@~3.0.2: version "3.0.3" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + resolved "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz" integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== dependencies: fill-range "^7.1.1" browser-stdout@1.3.1: version "1.3.1" - resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" + resolved "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz" integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== bs58@^4.0.0, bs58@^4.0.1: version "4.0.1" - resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" + resolved "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz" integrity sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw== dependencies: base-x "^3.0.2" +bs58@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/bs58/-/bs58-5.0.0.tgz" + integrity sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ== + dependencies: + base-x "^4.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" + resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== buffer-layout@^1.2.0, buffer-layout@^1.2.2: version "1.2.2" - resolved "https://registry.yarnpkg.com/buffer-layout/-/buffer-layout-1.2.2.tgz#b9814e7c7235783085f9ca4966a0cfff112259d5" + resolved "https://registry.npmjs.org/buffer-layout/-/buffer-layout-1.2.2.tgz" integrity sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA== -buffer@6.0.3, buffer@^6.0.3, 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" + resolved "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz" integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== dependencies: base64-js "^1.3.1" @@ -304,19 +506,45 @@ buffer@6.0.3, buffer@^6.0.3, buffer@~6.0.3: bufferutil@^4.0.1: version "4.0.9" - resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.9.tgz#6e81739ad48a95cad45a279588e13e95e24a800a" + resolved "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.9.tgz" integrity sha512-WDtdLmJvAuNNPzByAYpRo2rF1Mmradw6gvWsQKf63476DDXmomT9zUiGypLcG4ibIM67vhAj8jJRdbmEws2Aqw== dependencies: node-gyp-build "^4.3.0" +call-bind-apply-helpers@^1.0.0, call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz" + integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + +call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.7, call-bind@^1.0.8: + version "1.0.8" + resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz" + integrity sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww== + dependencies: + call-bind-apply-helpers "^1.0.0" + es-define-property "^1.0.0" + get-intrinsic "^1.2.4" + set-function-length "^1.2.2" + +call-bound@^1.0.2, call-bound@^1.0.3, call-bound@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz" + integrity sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg== + dependencies: + call-bind-apply-helpers "^1.0.2" + get-intrinsic "^1.3.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" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== chai@^4.3.4: version "4.5.0" - resolved "https://registry.yarnpkg.com/chai/-/chai-4.5.0.tgz#707e49923afdd9b13a8b0b47d33d732d13812fd8" + resolved "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz" integrity sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw== dependencies: assertion-error "^1.1.0" @@ -329,27 +557,27 @@ chai@^4.3.4: chalk@^4.1.0: version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== dependencies: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@^5.4.1: +chalk@^5.3.0, chalk@^5.4.1: version "5.6.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.6.2.tgz#b1238b6e23ea337af71c7f8a295db5af0c158aea" + resolved "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz" integrity sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA== check-error@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.3.tgz#a6502e4312a7ee969f646e83bb3ddd56281bd694" + resolved "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz" integrity sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg== dependencies: get-func-name "^2.0.2" chokidar@3.5.3: version "3.5.3" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" + resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz" integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== dependencies: anymatch "~3.1.2" @@ -364,7 +592,7 @@ chokidar@3.5.3: cliui@^7.0.2: version "7.0.4" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + resolved "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz" integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== dependencies: string-width "^4.2.0" @@ -373,129 +601,195 @@ cliui@^7.0.2: color-convert@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== dependencies: color-name "~1.1.4" color-name@~1.1.4: version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +commander@^12.1.0: + version "12.1.0" + resolved "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz" + integrity sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA== + commander@^14.0.0: version "14.0.2" - resolved "https://registry.yarnpkg.com/commander/-/commander-14.0.2.tgz#b71fd37fe4069e4c3c7c13925252ada4eba14e8e" + resolved "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz" integrity sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ== commander@^2.20.3: version "2.20.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz" 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" + resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== cross-fetch@^3.1.5: version "3.2.0" - resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.2.0.tgz#34e9192f53bc757d6614304d9e5e6fb4edb782e3" + resolved "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.2.0.tgz" integrity sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q== dependencies: node-fetch "^2.7.0" +debug@^4.3.3, debug@^4.3.4: + version "4.4.3" + resolved "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz" + integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== + dependencies: + ms "^2.1.3" + debug@4.3.3: version "4.3.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz" integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== dependencies: ms "2.1.2" decamelize@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" + resolved "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz" integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== deep-eql@^4.1.3: version "4.1.4" - resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.1.4.tgz#d0d3912865911bb8fac5afb4e3acfa6a28dc72b7" + resolved "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz" integrity sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg== dependencies: type-detect "^4.0.0" +define-data-property@^1.0.1, define-data-property@^1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz" + integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + gopd "^1.0.1" + +define-properties@^1.1.3, define-properties@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz" + integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== + dependencies: + define-data-property "^1.0.1" + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" + delay@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/delay/-/delay-5.0.0.tgz#137045ef1b96e5071060dd5be60bf9334436bd1d" + resolved "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz" integrity sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw== +diff@^3.1.0: + version "3.5.0" + resolved "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz" + integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== + diff@5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" + resolved "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz" 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== +dunder-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz" + integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== + dependencies: + call-bind-apply-helpers "^1.0.1" + es-errors "^1.3.0" + gopd "^1.2.0" emoji-regex@^8.0.0: version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== +es-define-property@^1.0.0, es-define-property@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz" + integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz" + integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== + dependencies: + es-errors "^1.3.0" + es6-promise@^4.0.3: version "4.2.8" - resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" + resolved "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz" integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== es6-promisify@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" + resolved "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz" integrity sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ== dependencies: es6-promise "^4.0.3" escalade@^3.1.1: version "3.2.0" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + resolved "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz" integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== 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" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== eventemitter3@^4.0.7: version "4.0.7" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== eventemitter3@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4" + resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz" integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== eyes@^0.1.8: version "0.1.8" - resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" + resolved "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz" integrity sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ== fast-stable-stringify@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/fast-stable-stringify/-/fast-stable-stringify-1.0.0.tgz#5c5543462b22aeeefd36d05b34e51c78cb86d313" + resolved "https://registry.npmjs.org/fast-stable-stringify/-/fast-stable-stringify-1.0.0.tgz" integrity sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag== +fastestsmallesttextencoderdecoder@^1.0.22: + version "1.0.22" + resolved "https://registry.npmjs.org/fastestsmallesttextencoderdecoder/-/fastestsmallesttextencoderdecoder-1.0.22.tgz" + integrity sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw== + +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== + fill-range@^7.1.1: version "7.1.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz" integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== dependencies: to-regex-range "^5.0.1" find-up@5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + resolved "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz" integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== dependencies: locate-path "^6.0.0" @@ -503,39 +797,75 @@ find-up@5.0.0: flat@^5.0.2: version "5.0.2" - resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" + resolved "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz" integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== +for-each@^0.3.5: + version "0.3.5" + resolved "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz" + integrity sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg== + dependencies: + is-callable "^1.2.7" + fs.realpath@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fsevents@~2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" - integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +generator-function@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz" + integrity sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g== get-caller-file@^2.0.5: version "2.0.5" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== get-func-name@^2.0.1, get-func-name@^2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41" + resolved "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz" integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== +get-intrinsic@^1.2.4, get-intrinsic@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz" + integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== + dependencies: + call-bind-apply-helpers "^1.0.2" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + function-bind "^1.1.2" + get-proto "^1.0.1" + gopd "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + math-intrinsics "^1.1.0" + +get-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz" + integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== + dependencies: + dunder-proto "^1.0.1" + es-object-atoms "^1.0.0" + glob-parent@~5.1.2: version "5.1.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== 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" + resolved "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz" integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== dependencies: fs.realpath "^1.0.0" @@ -545,98 +875,185 @@ glob@7.2.0: once "^1.3.0" path-is-absolute "^1.0.0" +gopd@^1.0.1, gopd@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz" + integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== + growl@1.10.5: version "1.10.5" - resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" + resolved "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz" 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" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== +has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz" + integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== + dependencies: + es-define-property "^1.0.0" + +has-symbols@^1.0.3, has-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz" + integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== + +has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== + dependencies: + has-symbols "^1.0.3" + +hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + he@1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + resolved "https://registry.npmjs.org/he/-/he-1.2.0.tgz" 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" + resolved "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz" 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" + resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== inflight@^1.0.4: version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== dependencies: once "^1.3.0" wrappy "1" -inherits@2: +inherits@^2.0.3, inherits@2: version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== +invariant@2.2.4: + version "2.2.4" + resolved "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz" + integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== + dependencies: + loose-envify "^1.0.0" + +is-arguments@^1.0.4: + version "1.2.0" + resolved "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz" + integrity sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA== + dependencies: + call-bound "^1.0.2" + has-tostringtag "^1.0.2" + is-binary-path@~2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + resolved "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz" integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== dependencies: binary-extensions "^2.0.0" +is-callable@^1.2.7: + version "1.2.7" + resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz" + integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== + is-extglob@^2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== is-fullwidth-code-point@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== +is-generator-function@^1.0.7: + version "1.1.2" + resolved "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz" + integrity sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA== + dependencies: + call-bound "^1.0.4" + generator-function "^2.0.0" + get-proto "^1.0.1" + has-tostringtag "^1.0.2" + safe-regex-test "^1.1.0" + is-glob@^4.0.1, is-glob@~4.0.1: version "4.0.3" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== dependencies: is-extglob "^2.1.1" +is-nan@^1.3.2: + version "1.3.2" + resolved "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz" + integrity sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + is-number@^7.0.0: version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== is-plain-obj@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" + resolved "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz" integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== +is-regex@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz" + integrity sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g== + dependencies: + call-bound "^1.0.2" + gopd "^1.2.0" + has-tostringtag "^1.0.2" + hasown "^2.0.2" + +is-typed-array@^1.1.3: + version "1.1.15" + resolved "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz" + integrity sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ== + dependencies: + which-typed-array "^1.1.16" + is-unicode-supported@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + resolved "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz" 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" + resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" 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" + resolved "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz" integrity sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w== jayson@^4.1.1: version "4.2.0" - resolved "https://registry.yarnpkg.com/jayson/-/jayson-4.2.0.tgz#b71762393fa40bc9637eaf734ca6f40d3b8c0c93" + resolved "https://registry.npmjs.org/jayson/-/jayson-4.2.0.tgz" integrity sha512-VfJ9t1YLwacIubLhONk0KFeosUBwstRWQ0IRT1KDjEjnVnSOVHC3uwugyV7L0c7R9lpVyrUGT2XWiBA1UTtpyg== dependencies: "@types/connect" "^3.4.33" @@ -652,81 +1069,98 @@ jayson@^4.1.1: uuid "^8.3.2" ws "^7.5.10" +"js-tokens@^3.0.0 || ^4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + js-yaml@4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz" integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== dependencies: argparse "^2.0.1" json-stringify-safe@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz" integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== json5@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" + resolved "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz" integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== dependencies: minimist "^1.2.0" locate-path@^6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + resolved "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz" integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== dependencies: p-locate "^5.0.0" log-symbols@4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + resolved "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz" integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== dependencies: chalk "^4.1.0" is-unicode-supported "^0.1.0" +loose-envify@^1.0.0: + version "1.4.0" + resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + loupe@^2.3.6: version "2.3.7" - resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.7.tgz#6e69b7d4db7d3ab436328013d37d1c8c3540c697" + resolved "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz" integrity sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA== dependencies: get-func-name "^2.0.1" make-error@^1.1.1: version "1.3.6" - resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz" 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" +math-intrinsics@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz" + integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== minimatch@^3.0.4: version "3.1.2" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: brace-expansion "^1.1.7" +minimatch@4.2.1: + version "4.2.1" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz" + integrity sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g== + dependencies: + brace-expansion "^1.1.7" + minimist@^1.2.0, minimist@^1.2.6: version "1.2.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== mkdirp@^0.5.1: version "0.5.6" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz" integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== dependencies: minimist "^1.2.6" -mocha@^9.0.3: +"mocha@^3.X.X || ^4.X.X || ^5.X.X || ^6.X.X || ^7.X.X || ^8.X.X || ^9.X.X || ^10.X.X || ^11.X.X", mocha@^9.0.3: version "9.2.2" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-9.2.2.tgz#d70db46bdb93ca57402c809333e5a84977a88fb9" + resolved "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz" integrity sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g== dependencies: "@ungap/promise-all-settled" "1.1.2" @@ -754,111 +1188,141 @@ mocha@^9.0.3: yargs-parser "20.2.4" yargs-unparser "2.0.0" +ms@^2.0.0, ms@^2.1.3, ms@2.1.3: + version "2.1.3" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + ms@2.1.2: version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3, ms@^2.0.0: - 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" + resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz" integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw== node-fetch@^2.7.0: version "2.7.0" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz" integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== dependencies: whatwg-url "^5.0.0" node-gyp-build@^4.3.0: version "4.8.4" - resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.4.tgz#8a70ee85464ae52327772a90d66c6077a900cfc8" + resolved "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz" integrity sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ== normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== +object-is@^1.1.5: + version "1.1.6" + resolved "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz" + integrity sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + +object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object.assign@^4.1.4: + version "4.1.7" + resolved "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz" + integrity sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.3" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + has-symbols "^1.1.0" + object-keys "^1.1.1" + once@^1.3.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== dependencies: wrappy "1" p-limit@^3.0.2: version "3.1.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== dependencies: yocto-queue "^0.1.0" p-locate@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + resolved "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz" integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== dependencies: p-limit "^3.0.2" pako@^2.0.3: version "2.1.0" - resolved "https://registry.yarnpkg.com/pako/-/pako-2.1.0.tgz#266cc37f98c7d883545d11335c00fbd4062c9a86" + resolved "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz" integrity sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug== path-exists@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" 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" + resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== pathval@^1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" + resolved "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz" integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== picomatch@^2.0.4, picomatch@^2.2.1: version "2.3.1" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== +possible-typed-array-names@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz" + integrity sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg== + prettier@^2.6.2: version "2.8.8" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" + resolved "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz" integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== randombytes@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + resolved "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz" integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== dependencies: safe-buffer "^5.1.0" readdirp@~3.6.0: version "3.6.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + resolved "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz" integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== dependencies: picomatch "^2.2.1" require-directory@^2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== rpc-websockets@^9.0.2: version "9.3.1" - resolved "https://registry.yarnpkg.com/rpc-websockets/-/rpc-websockets-9.3.1.tgz#d817a59d812f68bae1215740a3f78fcdd3813698" + resolved "https://registry.npmjs.org/rpc-websockets/-/rpc-websockets-9.3.1.tgz" integrity sha512-bY6a+i/lEtBJ/mUxwsCTgevoV1P0foXTVA7UoThzaIWbM+3NDqorf8NBWs5DmqKTFeA1IoNzgvkWjFCPgnzUiQ== dependencies: "@swc/helpers" "^0.5.11" @@ -874,19 +1338,40 @@ rpc-websockets@^9.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" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== +safe-regex-test@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz" + integrity sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + is-regex "^1.2.1" + serialize-javascript@6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" + resolved "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz" integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== dependencies: randombytes "^2.1.0" +set-function-length@^1.2.2: + version "1.2.2" + resolved "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" + source-map-support@^0.5.6: version "0.5.21" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz" integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== dependencies: buffer-from "^1.0.0" @@ -894,24 +1379,24 @@ source-map-support@^0.5.6: source-map@^0.6.0: version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== stream-chain@^2.2.5: version "2.2.5" - resolved "https://registry.yarnpkg.com/stream-chain/-/stream-chain-2.2.5.tgz#b30967e8f14ee033c5b9a19bbe8a2cba90ba0d09" + resolved "https://registry.npmjs.org/stream-chain/-/stream-chain-2.2.5.tgz" integrity sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA== stream-json@^1.9.1: version "1.9.1" - resolved "https://registry.yarnpkg.com/stream-json/-/stream-json-1.9.1.tgz#e3fec03e984a503718946c170db7d74556c2a187" + resolved "https://registry.npmjs.org/stream-json/-/stream-json-1.9.1.tgz" integrity sha512-uWkjJ+2Nt/LO9Z/JyKZbMusL8Dkh97uUBTv3AJQ74y07lVahLY4eEFsPsE97pxYBwr8nnjMAIch5eqI0gPShyw== dependencies: stream-chain "^2.2.5" string-width@^4.1.0, string-width@^4.2.0: version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== dependencies: emoji-regex "^8.0.0" @@ -920,70 +1405,70 @@ string-width@^4.1.0, string-width@^4.2.0: strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== dependencies: ansi-regex "^5.0.1" strip-bom@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz" integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== 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" + resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== superstruct@^0.15.4: version "0.15.5" - resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-0.15.5.tgz#0f0a8d3ce31313f0d84c6096cd4fa1bfdedc9dab" + resolved "https://registry.npmjs.org/superstruct/-/superstruct-0.15.5.tgz" integrity sha512-4AOeU+P5UuE/4nOUkmcQdW5y7i9ndt1cQd/3iUe+LTz3RxESf/W/5lg4B74HbDMMv8PHnPnGCQFH45kBcrQYoQ== superstruct@^2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-2.0.2.tgz#3f6d32fbdc11c357deff127d591a39b996300c54" + resolved "https://registry.npmjs.org/superstruct/-/superstruct-2.0.2.tgz" integrity sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A== -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" - supports-color@^7.1.0: version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== dependencies: has-flag "^4.0.0" +supports-color@8.1.1: + version "8.1.1" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz" + 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" + resolved "https://registry.npmjs.org/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz" integrity sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg== to-regex-range@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== dependencies: is-number "^7.0.0" toml@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/toml/-/toml-3.0.0.tgz#342160f1af1904ec9d204d03a5d61222d762c5ee" + resolved "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz" integrity sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w== tr46@~0.0.3: version "0.0.3" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz" integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== ts-mocha@^10.0.0: version "10.1.0" - resolved "https://registry.yarnpkg.com/ts-mocha/-/ts-mocha-10.1.0.tgz#17a1c055f5f7733fd82447c4420740db87221bc8" + resolved "https://registry.npmjs.org/ts-mocha/-/ts-mocha-10.1.0.tgz" integrity sha512-T0C0Xm3/WqCuF2tpa0GNGESTBoKZaiqdUP8guNv4ZY316AFXlyidnrzQ1LUrCT0Wb1i3J0zFTgOh/55Un44WdA== dependencies: ts-node "7.0.1" @@ -992,7 +1477,7 @@ ts-mocha@^10.0.0: ts-node@7.0.1: version "7.0.1" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-7.0.1.tgz#9562dc2d1e6d248d24bc55f773e3f614337d9baf" + resolved "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz" integrity sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw== dependencies: arrify "^1.0.0" @@ -1006,7 +1491,7 @@ ts-node@7.0.1: tsconfig-paths@^3.5.0: version "3.15.0" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4" + resolved "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz" integrity sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg== dependencies: "@types/json5" "^0.0.29" @@ -1016,64 +1501,88 @@ tsconfig-paths@^3.5.0: tslib@^2.8.0: version "2.8.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" + resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz" integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== type-detect@^4.0.0, type-detect@^4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.1.0.tgz#deb2453e8f08dcae7ae98c626b13dddb0155906c" + resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz" integrity sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw== -typescript@^5.7.3: +typescript@^5.7.3, typescript@>=5, typescript@>=5.3.3: version "5.9.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.9.3.tgz#5b4f59e15310ab17a216f5d6cf53ee476ede670f" + resolved "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz" integrity sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw== undici-types@~7.16.0: version "7.16.0" - resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-7.16.0.tgz#ffccdff36aea4884cbfce9a750a0580224f58a46" + resolved "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz" integrity sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw== -utf-8-validate@^5.0.2: +utf-8-validate@^5.0.2, 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" + resolved "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz" integrity sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ== dependencies: node-gyp-build "^4.3.0" +util@^0.12.5: + version "0.12.5" + resolved "https://registry.npmjs.org/util/-/util-0.12.5.tgz" + integrity sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA== + dependencies: + inherits "^2.0.3" + is-arguments "^1.0.4" + is-generator-function "^1.0.7" + is-typed-array "^1.1.3" + which-typed-array "^1.1.2" + uuid@^8.3.2: version "8.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== webidl-conversions@^3.0.0: version "3.0.1" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz" integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== whatwg-url@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz" integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== dependencies: tr46 "~0.0.3" webidl-conversions "^3.0.0" +which-typed-array@^1.1.16, which-typed-array@^1.1.2: + version "1.1.20" + resolved "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz" + integrity sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg== + dependencies: + available-typed-arrays "^1.0.7" + call-bind "^1.0.8" + call-bound "^1.0.4" + for-each "^0.3.5" + get-proto "^1.0.1" + gopd "^1.2.0" + has-tostringtag "^1.0.2" + which@2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" 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" + resolved "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz" integrity sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A== wrap-ansi@^7.0.0: version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== dependencies: ansi-styles "^4.0.0" @@ -1082,37 +1591,32 @@ wrap-ansi@^7.0.0: wrappy@1: version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== -ws@^7.5.10: +ws@*, ws@^7.5.10: version "7.5.10" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9" + resolved "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz" integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== ws@^8.5.0: version "8.18.3" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.3.tgz#b56b88abffde62791c639170400c93dcb0c95472" + resolved "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz" integrity sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg== y18n@^5.0.5: version "5.0.8" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== -yargs-parser@20.2.4: +yargs-parser@^20.2.2, yargs-parser@20.2.4: version "20.2.4" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz" integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== -yargs-parser@^20.2.2: - 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: version "2.0.0" - resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" + resolved "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz" integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== dependencies: camelcase "^6.0.0" @@ -1122,7 +1626,7 @@ yargs-unparser@2.0.0: yargs@16.2.0: version "16.2.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + resolved "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz" integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== dependencies: cliui "^7.0.2" @@ -1135,10 +1639,10 @@ yargs@16.2.0: yn@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/yn/-/yn-2.0.0.tgz#e5adabc8acf408f6385fc76495684c88e6af689a" + resolved "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz" integrity sha512-uTv8J/wiWTgUTg+9vLTi//leUl5vDQS6uii/emeTb2ssY7vl6QWf2fFbIIGjnhjvbdKlU0ed7QPgY1htTC86jQ== yocto-queue@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== From df3356f874251a1d09cc8cdc084fa91ca020a43f Mon Sep 17 00:00:00 2001 From: Alex Janiak Date: Tue, 17 Feb 2026 13:26:30 -0500 Subject: [PATCH 12/19] fix: clean up test file, use accountsPartial --- tests/redemption/devnet-test.ts | 125 ++++++++++++-------------------- 1 file changed, 45 insertions(+), 80 deletions(-) diff --git a/tests/redemption/devnet-test.ts b/tests/redemption/devnet-test.ts index 8626ae4..bf51372 100644 --- a/tests/redemption/devnet-test.ts +++ b/tests/redemption/devnet-test.ts @@ -3,13 +3,13 @@ * * Tests: * 1. Initialize vault with 9-decimal base, 6-decimal quote (USDC-like) - * 2. Redeem 1M base tokens at 0.0002758 price → ~275.8 quote + * 2. Redeem 1M base tokens at 0.000275 price → ~275 quote * 3. Error when redeeming more than vault balance * 4. Admin withdraws leftover quote */ import * as anchor from "@coral-xyz/anchor"; -import { Program } from "@coral-xyz/anchor"; +import { Program, BN } from "@coral-xyz/anchor"; import { PublicKey, Keypair, @@ -26,7 +26,6 @@ import { } from "@solana/spl-token"; import { expect } from "chai"; -// IDL will be loaded by Anchor import { Redemption } from "../../target/types/redemption"; const VAULT_SEED = Buffer.from("redemption"); @@ -34,17 +33,15 @@ const VAULT_SEED = Buffer.from("redemption"); // Test parameters const BASE_DECIMALS = 9; const QUOTE_DECIMALS = 6; -const UI_PRICE = 0.000275; // ~0.0002758 quote per base (rounded down) +const UI_PRICE = 0.000275; const PRICE = Math.floor(UI_PRICE * 10 ** QUOTE_DECIMALS); // 275 -const UI_REDEEM_AMOUNT = 1_000_000; // 1 million base tokens -const RAW_REDEEM_AMOUNT = UI_REDEEM_AMOUNT * 10 ** BASE_DECIMALS; -const EXPECTED_QUOTE = Math.floor( - (RAW_REDEEM_AMOUNT * PRICE) / 10 ** BASE_DECIMALS -); // ~275,800,000 raw = 275.8 USDC +const UI_REDEEM_AMOUNT = 1_000_000; +const RAW_REDEEM_AMOUNT = new BN(UI_REDEEM_AMOUNT).mul(new BN(10 ** BASE_DECIMALS)); +const EXPECTED_QUOTE = RAW_REDEEM_AMOUNT.mul(new BN(PRICE)).div(new BN(10 ** BASE_DECIMALS)); -// Initial vault deposit (enough for the test + some extra) -const INITIAL_QUOTE_DEPOSIT = 500 * 10 ** QUOTE_DECIMALS; // 500 quote tokens +// Initial vault deposit +const INITIAL_QUOTE_DEPOSIT = new BN(500 * 10 ** QUOTE_DECIMALS); describe("Redemption - Devnet Test", () => { const provider = anchor.AnchorProvider.env(); @@ -56,7 +53,6 @@ describe("Redemption - Devnet Test", () => { let baseMint: PublicKey; let quoteMint: PublicKey; let vault: PublicKey; - let vaultBump: number; let vaultQuoteAta: PublicKey; let vaultBaseAta: PublicKey; let adminQuoteAta: PublicKey; @@ -65,7 +61,7 @@ describe("Redemption - Devnet Test", () => { let userBaseAta: PublicKey; let userQuoteAta: PublicKey; - const nonce = Math.floor(Math.random() * 65535); // Random nonce for unique vault + const nonce = Math.floor(Math.random() * 65535); before(async () => { console.log("\n=== Setup ==="); @@ -84,7 +80,7 @@ describe("Redemption - Devnet Test", () => { ); console.log(`Base Mint (${BASE_DECIMALS} decimals): ${baseMint.toBase58()}`); - // Create quote mint (6 decimals, like USDC) + // Create quote mint (6 decimals) quoteMint = await createMint( provider.connection, admin.payer, @@ -95,13 +91,10 @@ describe("Redemption - Devnet Test", () => { console.log(`Quote Mint (${QUOTE_DECIMALS} decimals): ${quoteMint.toBase58()}`); // Derive vault PDA - [vault, vaultBump] = PublicKey.findProgramAddressSync( - [ - VAULT_SEED, - baseMint.toBuffer(), - quoteMint.toBuffer(), - Buffer.from(new Uint16Array([nonce]).buffer), - ], + const nonceBuffer = Buffer.alloc(2); + nonceBuffer.writeUInt16LE(nonce); + [vault] = PublicKey.findProgramAddressSync( + [VAULT_SEED, baseMint.toBuffer(), quoteMint.toBuffer(), nonceBuffer], program.programId ); console.log(`Vault PDA: ${vault.toBase58()}`); @@ -110,7 +103,7 @@ describe("Redemption - Devnet Test", () => { vaultQuoteAta = await getAssociatedTokenAddress(quoteMint, vault, true); vaultBaseAta = await getAssociatedTokenAddress(baseMint, vault, true); - // Setup admin quote ATA and mint tokens for deposit + // Setup admin quote ATA and mint tokens const adminQuoteAccount = await getOrCreateAssociatedTokenAccount( provider.connection, admin.payer, @@ -125,14 +118,12 @@ describe("Redemption - Devnet Test", () => { quoteMint, adminQuoteAta, admin.publicKey, - INITIAL_QUOTE_DEPOSIT + INITIAL_QUOTE_DEPOSIT.toNumber() ); - console.log(`Minted ${INITIAL_QUOTE_DEPOSIT / 10 ** QUOTE_DECIMALS} quote to admin`); + console.log(`Minted ${INITIAL_QUOTE_DEPOSIT.toNumber() / 10 ** QUOTE_DECIMALS} quote to admin`); // Setup test user userKeypair = Keypair.generate(); - - // Fund user with SOL const fundTx = await provider.connection.requestAirdrop( userKeypair.publicKey, LAMPORTS_PER_SOL @@ -149,8 +140,7 @@ describe("Redemption - Devnet Test", () => { ); userBaseAta = userBaseAccount.address; - // Mint base tokens to user (enough for test) - const userBaseMintAmount = 2_000_000 * 10 ** BASE_DECIMALS; // 2M base tokens + const userBaseMintAmount = 2_000_000 * 10 ** BASE_DECIMALS; await mintTo( provider.connection, admin.payer, @@ -168,14 +158,11 @@ describe("Redemption - Devnet Test", () => { console.log("\n=== Test: Initialize Vault ==="); await program.methods - .initialize(nonce, new anchor.BN(PRICE), new anchor.BN(INITIAL_QUOTE_DEPOSIT)) - .accounts({ + .initialize(nonce, new BN(PRICE), INITIAL_QUOTE_DEPOSIT) + .accountsPartial({ admin: admin.publicKey, - vault, baseMint, quoteMint, - vaultQuoteAta, - vaultBaseAta, adminQuoteAta, baseTokenProgram: TOKEN_PROGRAM_ID, quoteTokenProgram: TOKEN_PROGRAM_ID, @@ -184,7 +171,6 @@ describe("Redemption - Devnet Test", () => { }) .rpc(); - // Verify vault state const vaultAccount = await program.account.redemptionVault.fetch(vault); expect(vaultAccount.admin.toBase58()).to.equal(admin.publicKey.toBase58()); expect(vaultAccount.baseMint.toBase58()).to.equal(baseMint.toBase58()); @@ -192,32 +178,23 @@ describe("Redemption - Devnet Test", () => { expect(vaultAccount.price.toNumber()).to.equal(PRICE); expect(vaultAccount.nonce).to.equal(nonce); - // Verify vault quote balance const vaultQuoteBalance = await provider.connection.getTokenAccountBalance(vaultQuoteAta); - expect(Number(vaultQuoteBalance.value.amount)).to.equal(INITIAL_QUOTE_DEPOSIT); + expect(Number(vaultQuoteBalance.value.amount)).to.equal(INITIAL_QUOTE_DEPOSIT.toNumber()); - console.log(`✓ Vault initialized with ${INITIAL_QUOTE_DEPOSIT / 10 ** QUOTE_DECIMALS} quote tokens`); + console.log(`✓ Vault initialized with ${INITIAL_QUOTE_DEPOSIT.toNumber() / 10 ** QUOTE_DECIMALS} quote`); console.log(`✓ Price set to ${PRICE} (${UI_PRICE} UI)`); }); - it("redeems 1M base tokens for ~275.8 quote", async () => { + it("redeems 1M base tokens for ~275 quote", async () => { console.log("\n=== Test: Redeem 1M Base ==="); - const userQuoteBalanceBefore = await provider.connection - .getTokenAccountBalance(userQuoteAta) - .catch(() => ({ value: { amount: "0" } })); - await program.methods - .redeem(new anchor.BN(RAW_REDEEM_AMOUNT)) - .accounts({ + .redeem(RAW_REDEEM_AMOUNT) + .accountsPartial({ user: userKeypair.publicKey, - vault, baseMint, quoteMint, - vaultQuoteAta, - vaultBaseAta, userBaseAta, - userQuoteAta, baseTokenProgram: TOKEN_PROGRAM_ID, quoteTokenProgram: TOKEN_PROGRAM_ID, associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID, @@ -226,41 +203,33 @@ describe("Redemption - Devnet Test", () => { .signers([userKeypair]) .rpc(); - // Verify user received quote tokens const userQuoteBalance = await provider.connection.getTokenAccountBalance(userQuoteAta); - const received = Number(userQuoteBalance.value.amount) - Number(userQuoteBalanceBefore.value.amount); + const received = Number(userQuoteBalance.value.amount); console.log(`✓ Redeemed ${UI_REDEEM_AMOUNT.toLocaleString()} base tokens`); console.log(`✓ Received ${received / 10 ** QUOTE_DECIMALS} quote tokens`); - console.log(`✓ Expected ~${EXPECTED_QUOTE / 10 ** QUOTE_DECIMALS} quote tokens`); + console.log(`✓ Expected ${EXPECTED_QUOTE.toNumber() / 10 ** QUOTE_DECIMALS} quote tokens`); - // Allow small rounding tolerance - expect(received).to.be.closeTo(EXPECTED_QUOTE, 10); + expect(received).to.be.closeTo(EXPECTED_QUOTE.toNumber(), 10); - // Verify vault received base tokens const vaultBaseBalance = await provider.connection.getTokenAccountBalance(vaultBaseAta); - expect(Number(vaultBaseBalance.value.amount)).to.equal(RAW_REDEEM_AMOUNT); - console.log(`✓ Vault received ${RAW_REDEEM_AMOUNT / 10 ** BASE_DECIMALS} base tokens`); + expect(Number(vaultBaseBalance.value.amount)).to.equal(RAW_REDEEM_AMOUNT.toNumber()); + console.log(`✓ Vault received ${RAW_REDEEM_AMOUNT.toNumber() / 10 ** BASE_DECIMALS} base tokens`); }); it("fails when redeeming more than vault balance", async () => { console.log("\n=== Test: Insufficient Balance Error ==="); - // Try to redeem way more than vault has - const tooMuchBase = 10_000_000 * 10 ** BASE_DECIMALS; // 10M base = ~2758 quote needed + const tooMuchBase = new BN(10_000_000).mul(new BN(10 ** BASE_DECIMALS)); try { await program.methods - .redeem(new anchor.BN(tooMuchBase)) - .accounts({ + .redeem(tooMuchBase) + .accountsPartial({ user: userKeypair.publicKey, - vault, baseMint, quoteMint, - vaultQuoteAta, - vaultBaseAta, userBaseAta, - userQuoteAta, baseTokenProgram: TOKEN_PROGRAM_ID, quoteTokenProgram: TOKEN_PROGRAM_ID, associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID, @@ -270,8 +239,10 @@ describe("Redemption - Devnet Test", () => { .rpc(); expect.fail("Should have thrown InsufficientBalance error"); - } catch (err: any) { - expect(err.error?.errorCode?.code || err.message).to.include("InsufficientBalance"); + } catch (err: unknown) { + const error = err as { error?: { errorCode?: { code: string } }; message?: string }; + const errorCode = error.error?.errorCode?.code || error.message || ""; + expect(errorCode).to.include("InsufficientBalance"); console.log("✓ Correctly rejected: InsufficientBalance"); } }); @@ -279,16 +250,14 @@ describe("Redemption - Devnet Test", () => { it("admin withdraws leftover quote", async () => { console.log("\n=== Test: Admin Withdraw ==="); - // Check vault quote balance const vaultQuoteBefore = await provider.connection.getTokenAccountBalance(vaultQuoteAta); const vaultBaseBefore = await provider.connection.getTokenAccountBalance(vaultBaseAta); - const quoteToWithdraw = Number(vaultQuoteBefore.value.amount); - const baseToWithdraw = Number(vaultBaseBefore.value.amount); + const quoteToWithdraw = new BN(vaultQuoteBefore.value.amount); + const baseToWithdraw = new BN(vaultBaseBefore.value.amount); - console.log(`Vault quote balance: ${quoteToWithdraw / 10 ** QUOTE_DECIMALS}`); - console.log(`Vault base balance: ${baseToWithdraw / 10 ** BASE_DECIMALS}`); + console.log(`Vault quote balance: ${quoteToWithdraw.toNumber() / 10 ** QUOTE_DECIMALS}`); + console.log(`Vault base balance: ${baseToWithdraw.toNumber() / 10 ** BASE_DECIMALS}`); - // Setup admin base ATA if needed const adminBaseAccount = await getOrCreateAssociatedTokenAccount( provider.connection, admin.payer, @@ -298,14 +267,11 @@ describe("Redemption - Devnet Test", () => { adminBaseAta = adminBaseAccount.address; await program.methods - .withdraw(new anchor.BN(quoteToWithdraw), new anchor.BN(baseToWithdraw)) - .accounts({ + .withdraw(quoteToWithdraw, baseToWithdraw) + .accountsPartial({ admin: admin.publicKey, - vault, baseMint, quoteMint, - vaultQuoteAta, - vaultBaseAta, adminQuoteAta, adminBaseAta, baseTokenProgram: TOKEN_PROGRAM_ID, @@ -315,15 +281,14 @@ describe("Redemption - Devnet Test", () => { }) .rpc(); - // Verify vault is empty const vaultQuoteAfter = await provider.connection.getTokenAccountBalance(vaultQuoteAta); const vaultBaseAfter = await provider.connection.getTokenAccountBalance(vaultBaseAta); expect(Number(vaultQuoteAfter.value.amount)).to.equal(0); expect(Number(vaultBaseAfter.value.amount)).to.equal(0); - console.log(`✓ Admin withdrew ${quoteToWithdraw / 10 ** QUOTE_DECIMALS} quote tokens`); - console.log(`✓ Admin withdrew ${baseToWithdraw / 10 ** BASE_DECIMALS} base tokens`); + console.log(`✓ Admin withdrew ${quoteToWithdraw.toNumber() / 10 ** QUOTE_DECIMALS} quote`); + console.log(`✓ Admin withdrew ${baseToWithdraw.toNumber() / 10 ** BASE_DECIMALS} base`); console.log("✓ Vault is now empty"); }); From 424ad2239a086ab1a5d1bfc2be222a03149fd159 Mon Sep 17 00:00:00 2001 From: Alex Janiak Date: Tue, 17 Feb 2026 13:28:41 -0500 Subject: [PATCH 13/19] fix: use npx instead of yarn for test-redemption --- Anchor.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Anchor.toml b/Anchor.toml index 721449a..f1724ba 100644 --- a/Anchor.toml +++ b/Anchor.toml @@ -41,4 +41,4 @@ test-dao = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 \"tests/dao/**/*.ts\ test-fut = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 \"tests/futarchy/**/*.ts\"" test-vault = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 \"tests/vault/**/*.ts\"" test-svault = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 \"tests/svault/**/*.ts\"" -test-redemption = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 \"tests/redemption/**/*.ts\"" +test-redemption = "npx ts-mocha -p ./tsconfig.json -t 1000000 tests/redemption/**/*.ts" From 062c3daf09397d13fbd4c75abc7fcdd3cb33949f Mon Sep 17 00:00:00 2001 From: Alex Janiak Date: Tue, 17 Feb 2026 13:34:06 -0500 Subject: [PATCH 14/19] feat: add init-vault script Config vars: - BASE_MINT: FAIR token (9 dec) - QUOTE_MINT: USDC (6 dec) - PRICE: 276 (0.000276 USDC per FAIR) - DEPOSIT: 10 USDC - NONCE: configurable --- scripts/init-vault.ts | 134 ++++++++++++++++++++++++++++++++ tests/redemption/devnet-test.ts | 11 +++ 2 files changed, 145 insertions(+) create mode 100644 scripts/init-vault.ts diff --git a/scripts/init-vault.ts b/scripts/init-vault.ts new file mode 100644 index 0000000..9f97254 --- /dev/null +++ b/scripts/init-vault.ts @@ -0,0 +1,134 @@ +/** + * Initialize Redemption Vault Script + * + * Usage: + * ANCHOR_PROVIDER_URL=https://api.devnet.solana.com \ + * ANCHOR_WALLET=~/.config/solana/id.json \ + * npx ts-node scripts/init-vault.ts + */ + +import * as anchor from "@coral-xyz/anchor"; +import { Program, BN } from "@coral-xyz/anchor"; +import { PublicKey, SystemProgram } from "@solana/web3.js"; +import { + getAssociatedTokenAddress, + getOrCreateAssociatedTokenAccount, + TOKEN_PROGRAM_ID, + ASSOCIATED_TOKEN_PROGRAM_ID, +} from "@solana/spl-token"; + +import { Redemption } from "../target/types/redemption"; + +// ============================================ +// CONFIGURATION - Edit these values +// ============================================ + +// Base mint (token users send in) - FAIR token, 9 decimals +const BASE_MINT = new PublicKey("Fairr196TRbroavk2QhRb3RRDH1ZpdWC3yJDTDDestar"); +const BASE_DECIMALS = 9; + +// Quote mint (token users receive) - USDC, 6 decimals +const QUOTE_MINT = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"); +const QUOTE_DECIMALS = 6; + +// Price: 0.000276 USDC per FAIR token +// price = 0.000276 * 10^6 = 276 +const PRICE = 276; + +// Initial deposit: 10 USDC +const DEPOSIT_AMOUNT = 10 * 10 ** QUOTE_DECIMALS; // 10_000_000 + +// Vault nonce (change this to create multiple vaults) +const NONCE = 1; + +// ============================================ +// SCRIPT +// ============================================ + +const VAULT_SEED = Buffer.from("redemption"); + +async function main() { + // Setup provider + const provider = anchor.AnchorProvider.env(); + anchor.setProvider(provider); + + const program = anchor.workspace.Redemption as Program; + const admin = provider.wallet; + + console.log("=== Redemption Vault Initialization ===\n"); + console.log("Program ID:", program.programId.toBase58()); + console.log("Admin:", admin.publicKey.toBase58()); + console.log("Base Mint:", BASE_MINT.toBase58()); + console.log("Quote Mint:", QUOTE_MINT.toBase58()); + console.log("Price:", PRICE, `(${PRICE / 10 ** QUOTE_DECIMALS} quote per base)`); + console.log("Deposit:", DEPOSIT_AMOUNT / 10 ** QUOTE_DECIMALS, "quote tokens"); + console.log("Nonce:", NONCE); + console.log(); + + // Derive vault PDA + const nonceBuffer = Buffer.alloc(2); + nonceBuffer.writeUInt16LE(NONCE); + const [vault, bump] = PublicKey.findProgramAddressSync( + [VAULT_SEED, BASE_MINT.toBuffer(), QUOTE_MINT.toBuffer(), nonceBuffer], + program.programId + ); + console.log("Vault PDA:", vault.toBase58()); + + // Get vault ATAs + const vaultQuoteAta = await getAssociatedTokenAddress(QUOTE_MINT, vault, true); + const vaultBaseAta = await getAssociatedTokenAddress(BASE_MINT, vault, true); + console.log("Vault Quote ATA:", vaultQuoteAta.toBase58()); + console.log("Vault Base ATA:", vaultBaseAta.toBase58()); + + // Get admin quote ATA + const adminQuoteAccount = await getOrCreateAssociatedTokenAccount( + provider.connection, + (admin as anchor.Wallet).payer, + QUOTE_MINT, + admin.publicKey + ); + const adminQuoteAta = adminQuoteAccount.address; + console.log("Admin Quote ATA:", adminQuoteAta.toBase58()); + + // Check admin has enough quote tokens + const adminQuoteBalance = await provider.connection.getTokenAccountBalance(adminQuoteAta); + console.log("Admin Quote Balance:", Number(adminQuoteBalance.value.amount) / 10 ** QUOTE_DECIMALS); + + if (Number(adminQuoteBalance.value.amount) < DEPOSIT_AMOUNT) { + console.error("\n❌ Error: Insufficient quote token balance for deposit"); + console.error(` Need: ${DEPOSIT_AMOUNT / 10 ** QUOTE_DECIMALS}`); + console.error(` Have: ${Number(adminQuoteBalance.value.amount) / 10 ** QUOTE_DECIMALS}`); + process.exit(1); + } + + console.log("\nInitializing vault..."); + + // Initialize vault + const tx = await program.methods + .initialize(NONCE, new BN(PRICE), new BN(DEPOSIT_AMOUNT)) + .accountsPartial({ + admin: admin.publicKey, + baseMint: BASE_MINT, + quoteMint: QUOTE_MINT, + adminQuoteAta, + baseTokenProgram: TOKEN_PROGRAM_ID, + quoteTokenProgram: TOKEN_PROGRAM_ID, + associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID, + systemProgram: SystemProgram.programId, + }) + .rpc(); + + console.log("\n✅ Vault initialized!"); + console.log("Transaction:", tx); + console.log("\n=== Vault Details ==="); + console.log("Vault Address:", vault.toBase58()); + console.log("Base Mint:", BASE_MINT.toBase58()); + console.log("Quote Mint:", QUOTE_MINT.toBase58()); + console.log("Price:", PRICE); + console.log("Nonce:", NONCE); +} + +main().catch((err) => { + console.error("Error:", err); + process.exit(1); +}); diff --git a/tests/redemption/devnet-test.ts b/tests/redemption/devnet-test.ts index bf51372..16a2812 100644 --- a/tests/redemption/devnet-test.ts +++ b/tests/redemption/devnet-test.ts @@ -192,9 +192,13 @@ describe("Redemption - Devnet Test", () => { .redeem(RAW_REDEEM_AMOUNT) .accountsPartial({ user: userKeypair.publicKey, + vault, baseMint, quoteMint, + vaultQuoteAta, + vaultBaseAta, userBaseAta, + userQuoteAta, baseTokenProgram: TOKEN_PROGRAM_ID, quoteTokenProgram: TOKEN_PROGRAM_ID, associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID, @@ -227,9 +231,13 @@ describe("Redemption - Devnet Test", () => { .redeem(tooMuchBase) .accountsPartial({ user: userKeypair.publicKey, + vault, baseMint, quoteMint, + vaultQuoteAta, + vaultBaseAta, userBaseAta, + userQuoteAta, baseTokenProgram: TOKEN_PROGRAM_ID, quoteTokenProgram: TOKEN_PROGRAM_ID, associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID, @@ -270,8 +278,11 @@ describe("Redemption - Devnet Test", () => { .withdraw(quoteToWithdraw, baseToWithdraw) .accountsPartial({ admin: admin.publicKey, + vault, baseMint, quoteMint, + vaultQuoteAta, + vaultBaseAta, adminQuoteAta, adminBaseAta, baseTokenProgram: TOKEN_PROGRAM_ID, From 4b4177b0e20f708bfa2d3461dda6fcbb8d5fec55 Mon Sep 17 00:00:00 2001 From: Alex Janiak Date: Tue, 17 Feb 2026 14:01:21 -0500 Subject: [PATCH 15/19] feat: init-vault script reads from Anchor.toml No more env vars needed. Just run: npx tsx scripts/init-vault.ts Or override cluster: npx tsx scripts/init-vault.ts --cluster devnet --- package-lock.json | 1 + package.json | 1 + scripts/init-vault.ts | 97 ++++++++++++++++++++++++++++++++++++------- 3 files changed, 84 insertions(+), 15 deletions(-) diff --git a/package-lock.json b/package-lock.json index 371fc50..1cae865 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,6 +18,7 @@ "chai": "^4.3.4", "mocha": "^9.0.3", "prettier": "^2.6.2", + "toml": "^3.0.0", "ts-mocha": "^10.0.0", "typescript": "^5.7.3" } diff --git a/package.json b/package.json index 44ebcce..f33d659 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "chai": "^4.3.4", "mocha": "^9.0.3", "prettier": "^2.6.2", + "toml": "^3.0.0", "ts-mocha": "^10.0.0", "typescript": "^5.7.3" } diff --git a/scripts/init-vault.ts b/scripts/init-vault.ts index 9f97254..78c700f 100644 --- a/scripts/init-vault.ts +++ b/scripts/init-vault.ts @@ -1,21 +1,26 @@ /** * Initialize Redemption Vault Script * + * Reads config from Anchor.toml automatically. + * * Usage: - * ANCHOR_PROVIDER_URL=https://api.devnet.solana.com \ - * ANCHOR_WALLET=~/.config/solana/id.json \ - * npx ts-node scripts/init-vault.ts + * npx tsx scripts/init-vault.ts + * npx tsx scripts/init-vault.ts --cluster devnet + * npx tsx scripts/init-vault.ts --cluster mainnet */ import * as anchor from "@coral-xyz/anchor"; -import { Program, BN } from "@coral-xyz/anchor"; -import { PublicKey, SystemProgram } from "@solana/web3.js"; +import { Program, BN, Wallet } from "@coral-xyz/anchor"; +import { Connection, PublicKey, SystemProgram, Keypair } from "@solana/web3.js"; import { getAssociatedTokenAddress, getOrCreateAssociatedTokenAccount, TOKEN_PROGRAM_ID, ASSOCIATED_TOKEN_PROGRAM_ID, } from "@solana/spl-token"; +import * as fs from "fs"; +import * as path from "path"; +import * as toml from "toml"; import { Redemption } from "../target/types/redemption"; @@ -41,6 +46,46 @@ const DEPOSIT_AMOUNT = 10 * 10 ** QUOTE_DECIMALS; // 10_000_000 // Vault nonce (change this to create multiple vaults) const NONCE = 1; +// ============================================ +// LOAD ANCHOR.TOML CONFIG +// ============================================ + +interface AnchorToml { + provider: { + cluster: string; + wallet: string; + }; +} + +function loadAnchorToml(): AnchorToml { + const tomlPath = path.resolve(__dirname, "../Anchor.toml"); + const content = fs.readFileSync(tomlPath, "utf-8"); + return toml.parse(content) as AnchorToml; +} + +function resolveClusterUrl(cluster: string): string { + switch (cluster) { + case "localnet": + return "http://127.0.0.1:8899"; + case "devnet": + return "https://api.devnet.solana.com"; + case "mainnet": + case "mainnet-beta": + return "https://api.mainnet-beta.solana.com"; + default: + // Assume it's a URL + return cluster; + } +} + +function loadWallet(walletPath: string): Keypair { + const resolved = walletPath.startsWith("~") + ? walletPath.replace("~", process.env.HOME || "") + : path.resolve(__dirname, "..", walletPath); + const secretKey = JSON.parse(fs.readFileSync(resolved, "utf-8")); + return Keypair.fromSecretKey(Uint8Array.from(secretKey)); +} + // ============================================ // SCRIPT // ============================================ @@ -48,16 +93,38 @@ const NONCE = 1; const VAULT_SEED = Buffer.from("redemption"); async function main() { - // Setup provider - const provider = anchor.AnchorProvider.env(); + // Parse args + const args = process.argv.slice(2); + let clusterOverride: string | null = null; + for (let i = 0; i < args.length; i++) { + if (args[i] === "--cluster" && args[i + 1]) { + clusterOverride = args[i + 1]; + } + } + + // Load config from Anchor.toml + const config = loadAnchorToml(); + const cluster = clusterOverride || config.provider.cluster; + const clusterUrl = resolveClusterUrl(cluster); + const walletKeypair = loadWallet(config.provider.wallet); + const wallet = new Wallet(walletKeypair); + + // Setup connection and provider + const connection = new Connection(clusterUrl, "confirmed"); + const provider = new anchor.AnchorProvider(connection, wallet, { + commitment: "confirmed", + }); anchor.setProvider(provider); - const program = anchor.workspace.Redemption as Program; - const admin = provider.wallet; + // Load program from IDL + const idlPath = path.resolve(__dirname, "../target/idl/redemption.json"); + const idl = JSON.parse(fs.readFileSync(idlPath, "utf-8")); + const program = new Program(idl, provider); console.log("=== Redemption Vault Initialization ===\n"); + console.log("Cluster:", cluster, `(${clusterUrl})`); console.log("Program ID:", program.programId.toBase58()); - console.log("Admin:", admin.publicKey.toBase58()); + console.log("Admin:", wallet.publicKey.toBase58()); console.log("Base Mint:", BASE_MINT.toBase58()); console.log("Quote Mint:", QUOTE_MINT.toBase58()); console.log("Price:", PRICE, `(${PRICE / 10 ** QUOTE_DECIMALS} quote per base)`); @@ -82,16 +149,16 @@ async function main() { // Get admin quote ATA const adminQuoteAccount = await getOrCreateAssociatedTokenAccount( - provider.connection, - (admin as anchor.Wallet).payer, + connection, + walletKeypair, QUOTE_MINT, - admin.publicKey + wallet.publicKey ); const adminQuoteAta = adminQuoteAccount.address; console.log("Admin Quote ATA:", adminQuoteAta.toBase58()); // Check admin has enough quote tokens - const adminQuoteBalance = await provider.connection.getTokenAccountBalance(adminQuoteAta); + const adminQuoteBalance = await connection.getTokenAccountBalance(adminQuoteAta); console.log("Admin Quote Balance:", Number(adminQuoteBalance.value.amount) / 10 ** QUOTE_DECIMALS); if (Number(adminQuoteBalance.value.amount) < DEPOSIT_AMOUNT) { @@ -107,7 +174,7 @@ async function main() { const tx = await program.methods .initialize(NONCE, new BN(PRICE), new BN(DEPOSIT_AMOUNT)) .accountsPartial({ - admin: admin.publicKey, + admin: wallet.publicKey, baseMint: BASE_MINT, quoteMint: QUOTE_MINT, adminQuoteAta, From a37c4159624fe0c91a2cf3b8c94ac68f7528b93e Mon Sep 17 00:00:00 2001 From: Alex Janiak Date: Tue, 17 Feb 2026 14:08:49 -0500 Subject: [PATCH 16/19] simplify: hardcode RPC_URL and WALLET_PATH at top --- scripts/init-vault.ts | 108 +++++++++--------------------------------- 1 file changed, 23 insertions(+), 85 deletions(-) diff --git a/scripts/init-vault.ts b/scripts/init-vault.ts index 78c700f..b301521 100644 --- a/scripts/init-vault.ts +++ b/scripts/init-vault.ts @@ -1,12 +1,7 @@ /** * Initialize Redemption Vault Script * - * Reads config from Anchor.toml automatically. - * - * Usage: - * npx tsx scripts/init-vault.ts - * npx tsx scripts/init-vault.ts --cluster devnet - * npx tsx scripts/init-vault.ts --cluster mainnet + * Usage: npx tsx scripts/init-vault.ts */ import * as anchor from "@coral-xyz/anchor"; @@ -20,14 +15,19 @@ import { } from "@solana/spl-token"; import * as fs from "fs"; import * as path from "path"; -import * as toml from "toml"; import { Redemption } from "../target/types/redemption"; // ============================================ -// CONFIGURATION - Edit these values +// CONFIGURATION // ============================================ +// RPC URL +const RPC_URL = "https://api.mainnet-beta.solana.com"; + +// Wallet path +const WALLET_PATH = ".keys/authority.json"; + // Base mint (token users send in) - FAIR token, 9 decimals const BASE_MINT = new PublicKey("Fairr196TRbroavk2QhRb3RRDH1ZpdWC3yJDTDDestar"); const BASE_DECIMALS = 9; @@ -37,46 +37,19 @@ const QUOTE_MINT = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v") const QUOTE_DECIMALS = 6; // Price: 0.000276 USDC per FAIR token -// price = 0.000276 * 10^6 = 276 const PRICE = 276; // Initial deposit: 10 USDC -const DEPOSIT_AMOUNT = 10 * 10 ** QUOTE_DECIMALS; // 10_000_000 +const DEPOSIT_AMOUNT = 10 * 10 ** QUOTE_DECIMALS; -// Vault nonce (change this to create multiple vaults) +// Vault nonce const NONCE = 1; // ============================================ -// LOAD ANCHOR.TOML CONFIG +// SCRIPT // ============================================ -interface AnchorToml { - provider: { - cluster: string; - wallet: string; - }; -} - -function loadAnchorToml(): AnchorToml { - const tomlPath = path.resolve(__dirname, "../Anchor.toml"); - const content = fs.readFileSync(tomlPath, "utf-8"); - return toml.parse(content) as AnchorToml; -} - -function resolveClusterUrl(cluster: string): string { - switch (cluster) { - case "localnet": - return "http://127.0.0.1:8899"; - case "devnet": - return "https://api.devnet.solana.com"; - case "mainnet": - case "mainnet-beta": - return "https://api.mainnet-beta.solana.com"; - default: - // Assume it's a URL - return cluster; - } -} +const VAULT_SEED = Buffer.from("redemption"); function loadWallet(walletPath: string): Keypair { const resolved = walletPath.startsWith("~") @@ -86,68 +59,40 @@ function loadWallet(walletPath: string): Keypair { return Keypair.fromSecretKey(Uint8Array.from(secretKey)); } -// ============================================ -// SCRIPT -// ============================================ - -const VAULT_SEED = Buffer.from("redemption"); - async function main() { - // Parse args - const args = process.argv.slice(2); - let clusterOverride: string | null = null; - for (let i = 0; i < args.length; i++) { - if (args[i] === "--cluster" && args[i + 1]) { - clusterOverride = args[i + 1]; - } - } - - // Load config from Anchor.toml - const config = loadAnchorToml(); - const cluster = clusterOverride || config.provider.cluster; - const clusterUrl = resolveClusterUrl(cluster); - const walletKeypair = loadWallet(config.provider.wallet); + const walletKeypair = loadWallet(WALLET_PATH); const wallet = new Wallet(walletKeypair); - - // Setup connection and provider - const connection = new Connection(clusterUrl, "confirmed"); - const provider = new anchor.AnchorProvider(connection, wallet, { - commitment: "confirmed", - }); + const connection = new Connection(RPC_URL, "confirmed"); + const provider = new anchor.AnchorProvider(connection, wallet, { commitment: "confirmed" }); anchor.setProvider(provider); - // Load program from IDL const idlPath = path.resolve(__dirname, "../target/idl/redemption.json"); const idl = JSON.parse(fs.readFileSync(idlPath, "utf-8")); const program = new Program(idl, provider); console.log("=== Redemption Vault Initialization ===\n"); - console.log("Cluster:", cluster, `(${clusterUrl})`); + console.log("RPC:", RPC_URL); console.log("Program ID:", program.programId.toBase58()); console.log("Admin:", wallet.publicKey.toBase58()); console.log("Base Mint:", BASE_MINT.toBase58()); console.log("Quote Mint:", QUOTE_MINT.toBase58()); console.log("Price:", PRICE, `(${PRICE / 10 ** QUOTE_DECIMALS} quote per base)`); - console.log("Deposit:", DEPOSIT_AMOUNT / 10 ** QUOTE_DECIMALS, "quote tokens"); + console.log("Deposit:", DEPOSIT_AMOUNT / 10 ** QUOTE_DECIMALS, "USDC"); console.log("Nonce:", NONCE); console.log(); // Derive vault PDA const nonceBuffer = Buffer.alloc(2); nonceBuffer.writeUInt16LE(NONCE); - const [vault, bump] = PublicKey.findProgramAddressSync( + const [vault] = PublicKey.findProgramAddressSync( [VAULT_SEED, BASE_MINT.toBuffer(), QUOTE_MINT.toBuffer(), nonceBuffer], program.programId ); console.log("Vault PDA:", vault.toBase58()); - // Get vault ATAs + // Get ATAs const vaultQuoteAta = await getAssociatedTokenAddress(QUOTE_MINT, vault, true); const vaultBaseAta = await getAssociatedTokenAddress(BASE_MINT, vault, true); - console.log("Vault Quote ATA:", vaultQuoteAta.toBase58()); - console.log("Vault Base ATA:", vaultBaseAta.toBase58()); - - // Get admin quote ATA const adminQuoteAccount = await getOrCreateAssociatedTokenAccount( connection, walletKeypair, @@ -155,14 +100,13 @@ async function main() { wallet.publicKey ); const adminQuoteAta = adminQuoteAccount.address; - console.log("Admin Quote ATA:", adminQuoteAta.toBase58()); - // Check admin has enough quote tokens + // Check balance const adminQuoteBalance = await connection.getTokenAccountBalance(adminQuoteAta); - console.log("Admin Quote Balance:", Number(adminQuoteBalance.value.amount) / 10 ** QUOTE_DECIMALS); + console.log("Admin USDC Balance:", Number(adminQuoteBalance.value.amount) / 10 ** QUOTE_DECIMALS); if (Number(adminQuoteBalance.value.amount) < DEPOSIT_AMOUNT) { - console.error("\n❌ Error: Insufficient quote token balance for deposit"); + console.error("\n❌ Insufficient USDC balance"); console.error(` Need: ${DEPOSIT_AMOUNT / 10 ** QUOTE_DECIMALS}`); console.error(` Have: ${Number(adminQuoteBalance.value.amount) / 10 ** QUOTE_DECIMALS}`); process.exit(1); @@ -170,7 +114,6 @@ async function main() { console.log("\nInitializing vault..."); - // Initialize vault const tx = await program.methods .initialize(NONCE, new BN(PRICE), new BN(DEPOSIT_AMOUNT)) .accountsPartial({ @@ -187,12 +130,7 @@ async function main() { console.log("\n✅ Vault initialized!"); console.log("Transaction:", tx); - console.log("\n=== Vault Details ==="); - console.log("Vault Address:", vault.toBase58()); - console.log("Base Mint:", BASE_MINT.toBase58()); - console.log("Quote Mint:", QUOTE_MINT.toBase58()); - console.log("Price:", PRICE); - console.log("Nonce:", NONCE); + console.log("\nVault Address:", vault.toBase58()); } main().catch((err) => { From 0682bdb3b7c1e8dcb42f945bed1d11d4c044d8cb Mon Sep 17 00:00:00 2001 From: Alex Janiak Date: Tue, 17 Feb 2026 14:18:53 -0500 Subject: [PATCH 17/19] feat: add withdraw-vault script --- scripts/withdraw-vault.ts | 159 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 scripts/withdraw-vault.ts diff --git a/scripts/withdraw-vault.ts b/scripts/withdraw-vault.ts new file mode 100644 index 0000000..fca7911 --- /dev/null +++ b/scripts/withdraw-vault.ts @@ -0,0 +1,159 @@ +/** + * Withdraw All Funds from Redemption Vault + * + * Usage: npx tsx scripts/withdraw-vault.ts + */ + +import * as anchor from "@coral-xyz/anchor"; +import { Program, BN, Wallet } from "@coral-xyz/anchor"; +import { Connection, PublicKey, SystemProgram, Keypair } from "@solana/web3.js"; +import { + getAssociatedTokenAddress, + getOrCreateAssociatedTokenAccount, + TOKEN_PROGRAM_ID, + ASSOCIATED_TOKEN_PROGRAM_ID, +} from "@solana/spl-token"; +import * as fs from "fs"; +import * as path from "path"; + +import { Redemption } from "../target/types/redemption"; + +// ============================================ +// CONFIGURATION +// ============================================ + +// RPC URL +const RPC_URL = "https://api.mainnet-beta.solana.com"; + +// Wallet path +const WALLET_PATH = ".keys/authority.json"; + +// Base mint - FAIR token, 9 decimals +const BASE_MINT = new PublicKey("Fairr196TRbroavk2QhRb3RRDH1ZpdWC3yJDTDDestar"); +const BASE_DECIMALS = 9; + +// Quote mint - USDC, 6 decimals +const QUOTE_MINT = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"); +const QUOTE_DECIMALS = 6; + +// Vault nonce (must match the vault you want to withdraw from) +const NONCE = 1; + +// ============================================ +// SCRIPT +// ============================================ + +const VAULT_SEED = Buffer.from("redemption"); + +function loadWallet(walletPath: string): Keypair { + const resolved = walletPath.startsWith("~") + ? walletPath.replace("~", process.env.HOME || "") + : path.resolve(__dirname, "..", walletPath); + const secretKey = JSON.parse(fs.readFileSync(resolved, "utf-8")); + return Keypair.fromSecretKey(Uint8Array.from(secretKey)); +} + +async function main() { + const walletKeypair = loadWallet(WALLET_PATH); + const wallet = new Wallet(walletKeypair); + const connection = new Connection(RPC_URL, "confirmed"); + const provider = new anchor.AnchorProvider(connection, wallet, { commitment: "confirmed" }); + anchor.setProvider(provider); + + const idlPath = path.resolve(__dirname, "../target/idl/redemption.json"); + const idl = JSON.parse(fs.readFileSync(idlPath, "utf-8")); + const program = new Program(idl, provider); + + console.log("=== Redemption Vault Withdrawal ===\n"); + console.log("RPC:", RPC_URL); + console.log("Program ID:", program.programId.toBase58()); + console.log("Admin:", wallet.publicKey.toBase58()); + console.log("Nonce:", NONCE); + console.log(); + + // Derive vault PDA + const nonceBuffer = Buffer.alloc(2); + nonceBuffer.writeUInt16LE(NONCE); + const [vault] = PublicKey.findProgramAddressSync( + [VAULT_SEED, BASE_MINT.toBuffer(), QUOTE_MINT.toBuffer(), nonceBuffer], + program.programId + ); + console.log("Vault PDA:", vault.toBase58()); + + // Get vault ATAs + const vaultQuoteAta = await getAssociatedTokenAddress(QUOTE_MINT, vault, true); + const vaultBaseAta = await getAssociatedTokenAddress(BASE_MINT, vault, true); + + // Check vault balances + let quoteBalance = 0; + let baseBalance = 0; + + try { + const vaultQuoteBalance = await connection.getTokenAccountBalance(vaultQuoteAta); + quoteBalance = Number(vaultQuoteBalance.value.amount); + console.log("Vault USDC Balance:", quoteBalance / 10 ** QUOTE_DECIMALS); + } catch { + console.log("Vault USDC Balance: 0 (account doesn't exist)"); + } + + try { + const vaultBaseBalance = await connection.getTokenAccountBalance(vaultBaseAta); + baseBalance = Number(vaultBaseBalance.value.amount); + console.log("Vault FAIR Balance:", baseBalance / 10 ** BASE_DECIMALS); + } catch { + console.log("Vault FAIR Balance: 0 (account doesn't exist)"); + } + + if (quoteBalance === 0 && baseBalance === 0) { + console.log("\n⚠️ Vault is empty, nothing to withdraw."); + return; + } + + // Get/create admin ATAs + const adminQuoteAccount = await getOrCreateAssociatedTokenAccount( + connection, + walletKeypair, + QUOTE_MINT, + wallet.publicKey + ); + const adminQuoteAta = adminQuoteAccount.address; + + const adminBaseAccount = await getOrCreateAssociatedTokenAccount( + connection, + walletKeypair, + BASE_MINT, + wallet.publicKey + ); + const adminBaseAta = adminBaseAccount.address; + + console.log("\nWithdrawing all funds..."); + + const tx = await program.methods + .withdraw(new BN(quoteBalance), new BN(baseBalance)) + .accountsPartial({ + admin: wallet.publicKey, + vault, + baseMint: BASE_MINT, + quoteMint: QUOTE_MINT, + vaultQuoteAta, + vaultBaseAta, + adminQuoteAta, + adminBaseAta, + baseTokenProgram: TOKEN_PROGRAM_ID, + quoteTokenProgram: TOKEN_PROGRAM_ID, + associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID, + systemProgram: SystemProgram.programId, + }) + .rpc(); + + console.log("\n✅ Withdrawal complete!"); + console.log("Transaction:", tx); + console.log("\nWithdrew:"); + if (quoteBalance > 0) console.log(` ${quoteBalance / 10 ** QUOTE_DECIMALS} USDC`); + if (baseBalance > 0) console.log(` ${baseBalance / 10 ** BASE_DECIMALS} FAIR`); +} + +main().catch((err) => { + console.error("Error:", err); + process.exit(1); +}); From 7465a0762a418fb83cf81fb36532d182afeee80b Mon Sep 17 00:00:00 2001 From: Alex Janiak Date: Tue, 17 Feb 2026 15:36:33 -0500 Subject: [PATCH 18/19] feat: add deposit instruction for admin to top up vault - New deposit instruction in redemption program - deposit-vault.ts script for easy deposits - Admin can add more quote tokens anytime --- .../redemption/src/instructions/deposit.rs | 77 ++++++++++ programs/redemption/src/instructions/mod.rs | 2 + programs/redemption/src/lib.rs | 5 + scripts/deposit-vault.ts | 140 ++++++++++++++++++ 4 files changed, 224 insertions(+) create mode 100644 programs/redemption/src/instructions/deposit.rs create mode 100644 scripts/deposit-vault.ts diff --git a/programs/redemption/src/instructions/deposit.rs b/programs/redemption/src/instructions/deposit.rs new file mode 100644 index 0000000..b77ad4b --- /dev/null +++ b/programs/redemption/src/instructions/deposit.rs @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2025 Spice Finance Inc. + * + * This file is part of Z Combinator. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +use anchor_lang::prelude::*; +use anchor_spl::associated_token::AssociatedToken; +use anchor_spl::token_interface::{self, Mint, TokenAccount, TokenInterface, TransferChecked}; + +use crate::errors::RedemptionError; +use crate::state::{RedemptionVault, VAULT_SEED}; + +#[derive(Accounts)] +pub struct Deposit<'info> { + #[account(mut)] + pub admin: Signer<'info>, + + #[account( + seeds = [VAULT_SEED, vault.base_mint.as_ref(), vault.quote_mint.as_ref(), &vault.nonce.to_le_bytes()], + bump = vault.bump, + constraint = vault.admin == admin.key() @ RedemptionError::Unauthorized, + )] + pub vault: Account<'info, RedemptionVault>, + + pub quote_mint: InterfaceAccount<'info, Mint>, + + #[account( + mut, + associated_token::mint = quote_mint, + associated_token::authority = vault, + associated_token::token_program = quote_token_program, + )] + pub vault_quote_ata: InterfaceAccount<'info, TokenAccount>, + + #[account( + mut, + associated_token::mint = quote_mint, + associated_token::authority = admin, + associated_token::token_program = quote_token_program, + )] + pub admin_quote_ata: InterfaceAccount<'info, TokenAccount>, + + pub quote_token_program: Interface<'info, TokenInterface>, + pub associated_token_program: Program<'info, AssociatedToken>, +} + +/// Admin deposits additional quote tokens into the vault +pub fn deposit_handler(ctx: Context, amount: u64) -> Result<()> { + require!(amount > 0, RedemptionError::InvalidAmount); + + token_interface::transfer_checked( + CpiContext::new( + ctx.accounts.quote_token_program.to_account_info(), + TransferChecked { + from: ctx.accounts.admin_quote_ata.to_account_info(), + mint: ctx.accounts.quote_mint.to_account_info(), + to: ctx.accounts.vault_quote_ata.to_account_info(), + authority: ctx.accounts.admin.to_account_info(), + }, + ), + amount, + ctx.accounts.quote_mint.decimals, + ) +} diff --git a/programs/redemption/src/instructions/mod.rs b/programs/redemption/src/instructions/mod.rs index 489518d..ab68620 100644 --- a/programs/redemption/src/instructions/mod.rs +++ b/programs/redemption/src/instructions/mod.rs @@ -16,10 +16,12 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ +pub mod deposit; pub mod initialize; pub mod redeem; pub mod withdraw; +pub use deposit::*; pub use initialize::*; pub use redeem::*; pub use withdraw::*; diff --git a/programs/redemption/src/lib.rs b/programs/redemption/src/lib.rs index 3bb721b..082e6bc 100644 --- a/programs/redemption/src/lib.rs +++ b/programs/redemption/src/lib.rs @@ -37,6 +37,11 @@ pub mod redemption { initialize_handler(ctx, nonce, price, deposit) } + /// Admin deposits additional quote tokens into the vault + pub fn deposit(ctx: Context, amount: u64) -> Result<()> { + deposit_handler(ctx, amount) + } + /// Admin withdraws tokens from the vault pub fn withdraw(ctx: Context, quote_amount: u64, base_amount: u64) -> Result<()> { withdraw_handler(ctx, quote_amount, base_amount) diff --git a/scripts/deposit-vault.ts b/scripts/deposit-vault.ts new file mode 100644 index 0000000..1e03285 --- /dev/null +++ b/scripts/deposit-vault.ts @@ -0,0 +1,140 @@ +/** + * Deposit Additional Funds to Redemption Vault + * + * Usage: npx tsx scripts/deposit-vault.ts + */ + +import * as anchor from "@coral-xyz/anchor"; +import { Program, BN, Wallet } from "@coral-xyz/anchor"; +import { Connection, PublicKey, SystemProgram, Keypair } from "@solana/web3.js"; +import { + getAssociatedTokenAddress, + getOrCreateAssociatedTokenAccount, + TOKEN_PROGRAM_ID, + ASSOCIATED_TOKEN_PROGRAM_ID, +} from "@solana/spl-token"; +import * as fs from "fs"; +import * as path from "path"; + +import { Redemption } from "../target/types/redemption"; + +// ============================================ +// CONFIGURATION +// ============================================ + +// RPC URL +const RPC_URL = "https://api.mainnet-beta.solana.com"; + +// Wallet path +const WALLET_PATH = ".keys/authority.json"; + +// Base mint - FAIR token, 9 decimals +const BASE_MINT = new PublicKey("Fairr196TRbroavk2QhRb3RRDH1ZpdWC3yJDTDDestar"); + +// Quote mint - USDC, 6 decimals +const QUOTE_MINT = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"); +const QUOTE_DECIMALS = 6; + +// Vault nonce (must match the vault you want to deposit to) +const NONCE = 1; + +// Amount to deposit (in USDC) +const DEPOSIT_AMOUNT = 100 * 10 ** QUOTE_DECIMALS; // 100 USDC + +// ============================================ +// SCRIPT +// ============================================ + +const VAULT_SEED = Buffer.from("redemption"); + +function loadWallet(walletPath: string): Keypair { + const resolved = walletPath.startsWith("~") + ? walletPath.replace("~", process.env.HOME || "") + : path.resolve(__dirname, "..", walletPath); + const secretKey = JSON.parse(fs.readFileSync(resolved, "utf-8")); + return Keypair.fromSecretKey(Uint8Array.from(secretKey)); +} + +async function main() { + const walletKeypair = loadWallet(WALLET_PATH); + const wallet = new Wallet(walletKeypair); + const connection = new Connection(RPC_URL, "confirmed"); + const provider = new anchor.AnchorProvider(connection, wallet, { commitment: "confirmed" }); + anchor.setProvider(provider); + + const idlPath = path.resolve(__dirname, "../target/idl/redemption.json"); + const idl = JSON.parse(fs.readFileSync(idlPath, "utf-8")); + const program = new Program(idl, provider); + + console.log("=== Redemption Vault Deposit ===\n"); + console.log("RPC:", RPC_URL); + console.log("Program ID:", program.programId.toBase58()); + console.log("Admin:", wallet.publicKey.toBase58()); + console.log("Deposit Amount:", DEPOSIT_AMOUNT / 10 ** QUOTE_DECIMALS, "USDC"); + console.log("Nonce:", NONCE); + console.log(); + + // Derive vault PDA + const nonceBuffer = Buffer.alloc(2); + nonceBuffer.writeUInt16LE(NONCE); + const [vault] = PublicKey.findProgramAddressSync( + [VAULT_SEED, BASE_MINT.toBuffer(), QUOTE_MINT.toBuffer(), nonceBuffer], + program.programId + ); + console.log("Vault PDA:", vault.toBase58()); + + // Get vault quote ATA + const vaultQuoteAta = await getAssociatedTokenAddress(QUOTE_MINT, vault, true); + + // Check current vault balance + try { + const vaultQuoteBalance = await connection.getTokenAccountBalance(vaultQuoteAta); + console.log("Current Vault USDC Balance:", Number(vaultQuoteBalance.value.amount) / 10 ** QUOTE_DECIMALS); + } catch { + console.log("Current Vault USDC Balance: 0"); + } + + // Get admin quote ATA + const adminQuoteAccount = await getOrCreateAssociatedTokenAccount( + connection, + walletKeypair, + QUOTE_MINT, + wallet.publicKey + ); + const adminQuoteAta = adminQuoteAccount.address; + + // Check admin balance + const adminQuoteBalance = await connection.getTokenAccountBalance(adminQuoteAta); + console.log("Admin USDC Balance:", Number(adminQuoteBalance.value.amount) / 10 ** QUOTE_DECIMALS); + + if (Number(adminQuoteBalance.value.amount) < DEPOSIT_AMOUNT) { + console.error("\n❌ Insufficient USDC balance"); + console.error(` Need: ${DEPOSIT_AMOUNT / 10 ** QUOTE_DECIMALS}`); + console.error(` Have: ${Number(adminQuoteBalance.value.amount) / 10 ** QUOTE_DECIMALS}`); + process.exit(1); + } + + console.log("\nDepositing..."); + + const tx = await program.methods + .deposit(new BN(DEPOSIT_AMOUNT)) + .accountsPartial({ + admin: wallet.publicKey, + vault, + quoteMint: QUOTE_MINT, + vaultQuoteAta, + adminQuoteAta, + quoteTokenProgram: TOKEN_PROGRAM_ID, + associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID, + }) + .rpc(); + + console.log("\n✅ Deposit complete!"); + console.log("Transaction:", tx); + console.log("\nDeposited:", DEPOSIT_AMOUNT / 10 ** QUOTE_DECIMALS, "USDC"); +} + +main().catch((err) => { + console.error("Error:", err); + process.exit(1); +}); From 35f4d2bc5d43072101b18dbecf689fd6396346b6 Mon Sep 17 00:00:00 2001 From: handsdiff <239876380+handsdiff@users.noreply.github.com> Date: Sun, 22 Feb 2026 19:46:42 -0500 Subject: [PATCH 19/19] fix number --- scripts/withdraw-vault.ts | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/scripts/withdraw-vault.ts b/scripts/withdraw-vault.ts index fca7911..a8d3601 100644 --- a/scripts/withdraw-vault.ts +++ b/scripts/withdraw-vault.ts @@ -37,7 +37,7 @@ const QUOTE_MINT = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v") const QUOTE_DECIMALS = 6; // Vault nonce (must match the vault you want to withdraw from) -const NONCE = 1; +const NONCE = 2; // ============================================ // SCRIPT @@ -84,27 +84,27 @@ async function main() { const vaultQuoteAta = await getAssociatedTokenAddress(QUOTE_MINT, vault, true); const vaultBaseAta = await getAssociatedTokenAddress(BASE_MINT, vault, true); - // Check vault balances - let quoteBalance = 0; - let baseBalance = 0; + // Check vault balances (keep as strings to avoid Number overflow with large amounts) + let quoteBalance = "0"; + let baseBalance = "0"; try { const vaultQuoteBalance = await connection.getTokenAccountBalance(vaultQuoteAta); - quoteBalance = Number(vaultQuoteBalance.value.amount); - console.log("Vault USDC Balance:", quoteBalance / 10 ** QUOTE_DECIMALS); + quoteBalance = vaultQuoteBalance.value.amount; + console.log("Vault USDC Balance:", vaultQuoteBalance.value.uiAmountString); } catch { console.log("Vault USDC Balance: 0 (account doesn't exist)"); } try { const vaultBaseBalance = await connection.getTokenAccountBalance(vaultBaseAta); - baseBalance = Number(vaultBaseBalance.value.amount); - console.log("Vault FAIR Balance:", baseBalance / 10 ** BASE_DECIMALS); + baseBalance = vaultBaseBalance.value.amount; + console.log("Vault FAIR Balance:", vaultBaseBalance.value.uiAmountString); } catch { console.log("Vault FAIR Balance: 0 (account doesn't exist)"); } - if (quoteBalance === 0 && baseBalance === 0) { + if (quoteBalance === "0" && baseBalance === "0") { console.log("\n⚠️ Vault is empty, nothing to withdraw."); return; } @@ -149,8 +149,8 @@ async function main() { console.log("\n✅ Withdrawal complete!"); console.log("Transaction:", tx); console.log("\nWithdrew:"); - if (quoteBalance > 0) console.log(` ${quoteBalance / 10 ** QUOTE_DECIMALS} USDC`); - if (baseBalance > 0) console.log(` ${baseBalance / 10 ** BASE_DECIMALS} FAIR`); + if (quoteBalance !== "0") console.log(` ${Number(quoteBalance) / 10 ** QUOTE_DECIMALS} USDC`); + if (baseBalance !== "0") console.log(` ${Number(baseBalance) / 10 ** BASE_DECIMALS} FAIR`); } main().catch((err) => {