diff --git a/flake.nix b/flake.nix index 4e016bac8..32bf410c8 100644 --- a/flake.nix +++ b/flake.nix @@ -134,25 +134,6 @@ }; inherit craneLib; }; - - movementswap-core = pkgs.stdenv.mkDerivation { - pname = "movementswap-core"; - version = "branch-main"; - src = pkgs.fetchFromGitHub { - owner = "movementlabsxyz"; - repo = "movementswap-core"; - rev = "b05e21ad220de11af266696bb3b00ab8b0893e24"; - sha256 = "sha256-hSmzcr3ZJIVCuOt5x+Run3o3xyUtS6qqQiE8Tsefb9g="; - }; - installPhase = '' - cp -r . $out - ''; - meta = with pkgs.lib; { - description = "Movementswap core repository"; - homepage = "https://github.com/movementlabsxyz/movementswap-core"; - license = licenses.asl20; - }; - }; in with pkgs; { @@ -187,7 +168,6 @@ OPENSSL_DEV = pkgs.openssl.dev; PKG_CONFIG_PATH = "${pkgs.openssl.dev}/lib/pkgconfig"; MONZA_APTOS_PATH = monza-aptos; - MOVEMENT_SWAP_PATH = movementswap-core; buildInputs = [] ++buildDependencies ++sysDependencies ++testDependencies; nativeBuildInputs = [] ++buildDependencies ++sysDependencies; @@ -198,18 +178,8 @@ // # Movement Swap Core DOT_MOVEMENT_PATH=$(pwd)/.movement mkdir -p $DOT_MOVEMENT_PATH - export $MOVEMENT_SWAP_PATH - echo "Building movement-swap-core..." - cp -R "$MOVEMENT_SWAP_PATH" $DOT_MOVEMENT_PATH/movementswap-core - chmod -R 755 $DOT_MOVEMENT_PATH/movementswap-core - WORKING_DIRECTORY=$(pwd) - cd $DOT_MOVEMENT_PATH/movementswap-core/tests/typescript-sdk - npm install pnpm - pnpm install - cd $WORKING_DIRECTORY echo "Monza Aptos path: $MONZA_APTOS_PATH" - echo "Movementswap path: $MOVEMENT_SWAP_PATH" cat <<'EOF' _ _ __ _ _ ____ _ _ ____ __ _ ____ ( \/ ) / \ / )( \( __)( \/ )( __)( ( \(_ _) diff --git a/networks/suzuka/suzuka-client/.aptos/config.yaml b/networks/suzuka/suzuka-client/.aptos/config.yaml index f4f27c820..682a7bcb5 100644 --- a/networks/suzuka/suzuka-client/.aptos/config.yaml +++ b/networks/suzuka/suzuka-client/.aptos/config.yaml @@ -4,5 +4,5 @@ profiles: private_key: "0xfbc0596f14bd008b20269a52e22311842453ccd3dd64575bc656dc8e755244b7" public_key: "0xbe11803a40d33723d0a294cb657dd2477af4c31cae019f1e4bd783084033d1f6" account: 00da3c48fe5d426966ae33945eff05cdbc5fb9a986c92d26a9d7665d99efdeff - rest_url: "http://0.0.0.0:30731/" - faucet_url: "http://0.0.0.0:30732/" + rest_url: "http://localhost:30731/" + faucet_url: "http://localhost:30732/" diff --git a/networks/suzuka/suzuka-client/log_file.txt b/networks/suzuka/suzuka-client/log_file.txt index ca7d9d9e9..e69de29bb 100644 --- a/networks/suzuka/suzuka-client/log_file.txt +++ b/networks/suzuka/suzuka-client/log_file.txt @@ -1,10 +0,0 @@ -2024-06-18T17:41:50.972997Z  WARN suzuka_client::load_soak_testing: Error during scenario spawning: task 4 panicked -2024-06-18T17:41:50.973007Z  WARN suzuka_client::load_soak_testing: Error during scenario spawning: task 9 panicked -2024-06-18T17:41:50.973034Z  WARN suzuka_client::load_soak_testing: Error during scenario spawning: task 1 panicked -2024-06-18T17:41:50.973131Z  WARN suzuka_client::load_soak_testing: Error during scenario spawning: task 2 panicked -2024-06-18T17:41:50.973141Z  WARN suzuka_client::load_soak_testing: Error during scenario spawning: task 6 panicked -2024-06-18T17:41:50.973135Z  WARN suzuka_client::load_soak_testing: Error during scenario spawning: task 10 panicked -2024-06-18T17:41:50.973155Z  WARN suzuka_client::load_soak_testing: Error during scenario spawning: task 8 panicked -2024-06-18T17:41:50.973184Z  WARN suzuka_client::load_soak_testing: Error during scenario spawning: task 3 panicked -2024-06-18T17:41:50.973201Z  WARN suzuka_client::load_soak_testing: Error during scenario spawning: task 5 panicked -2024-06-18T17:41:50.973216Z  WARN suzuka_client::load_soak_testing: Error during scenario spawning: task 7 panicked diff --git a/networks/suzuka/suzuka-client/src/load_soak_testing/mod.rs b/networks/suzuka/suzuka-client/src/load_soak_testing/mod.rs index 0ee7fb255..f4e21433c 100644 --- a/networks/suzuka/suzuka-client/src/load_soak_testing/mod.rs +++ b/networks/suzuka/suzuka-client/src/load_soak_testing/mod.rs @@ -167,16 +167,20 @@ pub fn execute_test(config: ExecutionConfig, create_scenario: Arc 0).then_some(res)) .collect(); - - let average_exec_time = no_zero_exec_time - .iter() - .map(|res| res.average_execution_time_milli) - .sum::() - / no_zero_exec_time.len() as u128; - let metrics_average_exec_time = serde_json::to_string(&average_exec_time) - .unwrap_or("Metric execution result serialization error.".to_string()); - tracing::info!(target:EXEC_LOG_FILTER, metrics_average_exec_time); - tracing::info!("Scenarios execution average_exec_time:{metrics_average_exec_time}"); + if no_zero_exec_time.len() > 0 { + let average_exec_time = no_zero_exec_time + .iter() + .map(|res| res.average_execution_time_milli) + .sum::() + / no_zero_exec_time.len() as u128; + let metrics_average_exec_time = serde_json::to_string(&average_exec_time) + .unwrap_or("Metric execution result serialization error.".to_string()); + tracing::info!(target:EXEC_LOG_FILTER, metrics_average_exec_time); + tracing::info!("Scenarios execution average_exec_time:{metrics_average_exec_time}"); + } else { + tracing::info!(target:EXEC_LOG_FILTER, "No scenario has been executed"); + tracing::info!("Scenarios execution: No scenario has been executed"); + }; tracing::info!("End test scenario execution."); } @@ -220,8 +224,8 @@ impl TestClient { // max_scenarios - min_scenarios scenarios run part-time depending on the number of cycle. // Part-time scenario duration max: Duration / (number_cycle * 2) // scenario start delta: (Part-time scenario duration max * scenario index / nb scenario) + (Duration * current cycle / nb cycle) - let _number_part_time_scenario: u32 = (max_scenarios - min_scenarios) as u32; - let _parttime_scenario_duration = duration / (number_cycle * 2); + let number_part_time_scenario: u32 = (max_scenarios - min_scenarios) as u32; + let parttime_scenario_duration = duration / (number_cycle * 2); vec![] } } @@ -384,10 +388,11 @@ impl ClientExecResult { .into_iter() .filter_map(|s| if s.is_ok() { Some(s.elapse_millli) } else { None }) .collect(); - ok_scenario.iter().sum::() / ok_scenario.len() as u128 + ok_scenario.iter().sum::() + // / ok_scenario.len() as u128 } else { tracing::warn!("No result available average exec time is 0"); 0 } } -} +} \ No newline at end of file diff --git a/networks/suzuka/suzuka-client/src/tests/hey-partners/.env b/networks/suzuka/suzuka-client/src/tests/hey-partners/.env new file mode 100644 index 000000000..f9bd97679 --- /dev/null +++ b/networks/suzuka/suzuka-client/src/tests/hey-partners/.env @@ -0,0 +1,5 @@ +SWAP_DEPLOYER=0xef115fb777122a4983d54e5c420e77c80a83c1dc43d4a42d484c9aa9b3678e5c +RESOURCE_ACCOUNT_DEPLOYER=0x3fd7802c63826ea94b8102e71f95c562f2d4ac5cbd76537a6bb4224b8c74791d +PRIVATE_KEY=0x47d6b309dfcc38a09ab9477f624e8b6ede5ea1ee9d63911c63fc715c1c8f7a26 +FULLNODE=http://localhost:30731 +FAUCET=http://localhost:30733 \ No newline at end of file diff --git a/networks/suzuka/suzuka-client/src/tests/hey-partners/.gitignore b/networks/suzuka/suzuka-client/src/tests/hey-partners/.gitignore new file mode 100644 index 000000000..74a5f2580 --- /dev/null +++ b/networks/suzuka/suzuka-client/src/tests/hey-partners/.gitignore @@ -0,0 +1,4 @@ +*/build/ +.movement aptos + +.aptos/ diff --git a/networks/suzuka/suzuka-client/src/tests/hey-partners/Faucet/Move.toml b/networks/suzuka/suzuka-client/src/tests/hey-partners/Faucet/Move.toml new file mode 100644 index 000000000..66f2bb22d --- /dev/null +++ b/networks/suzuka/suzuka-client/src/tests/hey-partners/Faucet/Move.toml @@ -0,0 +1,9 @@ +[package] +name = "Faucet" +version = "0.3.0" + +[dependencies] +AptosFramework = { git = "https://github.com/aptos-labs/aptos-core.git", subdir = "aptos-move/framework/aptos-framework/", rev = "bbce0f188d7bef08218f1fc1f46bbd3676b5c74b" } + +[addresses] +SwapDeployer = "_" diff --git a/networks/suzuka/suzuka-client/src/tests/hey-partners/Faucet/sources/faucet.move b/networks/suzuka/suzuka-client/src/tests/hey-partners/Faucet/sources/faucet.move new file mode 100644 index 000000000..dd545231a --- /dev/null +++ b/networks/suzuka/suzuka-client/src/tests/hey-partners/Faucet/sources/faucet.move @@ -0,0 +1,313 @@ +/// Basic faucet, allows to request coins between intervals. +module SwapDeployer::FaucetV1 { + use std::signer; + use aptos_framework::timestamp; + use aptos_framework::coin::{Self, Coin}; + + // Errors. + + /// When Faucet already exists on account. + const ERR_FAUCET_EXISTS: u64 = 100; + + /// When Faucet doesn't exists on account. + const ERR_FAUCET_NOT_EXISTS: u64 = 101; + + /// When user already got coins and currently restricted to request more funds. + const ERR_RESTRICTED: u64 = 102; + + /// Faucet data. + struct Faucet has key { + /// Faucet balance. + deposit: Coin, + /// How much coins should be sent to user per request. + per_request: u64, + /// Period between requests to faucet in seconds. + period: u64, + } + + /// If user has this resource on his account - he's not able to get more funds if (current_timestamp < since + period). + struct Restricted has key { + since: u64, + } + + // Public functions. + + /// Create a new faucet on `account` address. + /// * `deposit` - initial coins on faucet balance. + /// * `per_request` - how much funds should be distributed per user request. + /// * `period` - interval allowed between requests for specific user. + public fun create_faucet_internal(account: &signer, deposit: Coin, per_request: u64, period: u64) { + let account_addr = signer::address_of(account); + + assert!(!exists>(account_addr), ERR_FAUCET_EXISTS); + + move_to(account, Faucet { + deposit, + per_request, + period + }); + } + + /// Change settings of faucet `CoinType`. + /// * `per_request` - how much funds should be distributed per user request. + /// * `period` - interval allowed between requests for specific user. + public fun change_settings_internal(account: &signer, per_request: u64, period: u64) acquires Faucet { + let account_addr = signer::address_of(account); + + assert!(exists>(account_addr), ERR_FAUCET_NOT_EXISTS); + + let faucet = borrow_global_mut>(account_addr); + faucet.per_request = per_request; + faucet.period = period; + } + + /// Deposist more coins `CoinType` to faucet. + public fun deposit_internal(faucet_addr: address, deposit: Coin) acquires Faucet { + assert!(exists>(faucet_addr), ERR_FAUCET_NOT_EXISTS); + + let faucet = borrow_global_mut>(faucet_addr); + coin::merge(&mut faucet.deposit, deposit); + } + + /// Requests coins `CoinType` from faucet `faucet_addr`. + public fun request_internal(account: &signer, faucet_addr: address): Coin acquires Faucet, Restricted { + let account_addr = signer::address_of(account); + + assert!(exists>(faucet_addr), ERR_FAUCET_NOT_EXISTS); + + let faucet = borrow_global_mut>(faucet_addr); + let coins = coin::extract(&mut faucet.deposit, faucet.per_request); + + let now = timestamp::now_seconds(); + + if (exists>(account_addr)) { + let restricted = borrow_global_mut>(account_addr); + assert!(restricted.since + faucet.period <= now, ERR_RESTRICTED); + restricted.since = now; + } else { + move_to(account, Restricted { + since: now, + }); + }; + + coins + } + + // Scripts. + + /// Creates new faucet on `account` address for coin `CoinType`. + /// * `account` - account which creates + /// * `per_request` - how much funds should be distributed per user request. + /// * `period` - interval allowed between requests for specific user. + public entry fun create_faucet(account: &signer, amount_to_deposit: u64, per_request: u64, period: u64) { + let coins = coin::withdraw(account, amount_to_deposit); + + create_faucet_internal(account, coins, per_request, period); + } + + /// Changes faucet settings on `account`. + public entry fun change_settings(account: &signer, per_request: u64, period: u64) acquires Faucet { + change_settings_internal(account, per_request, period); + } + + /// Deposits coins `CoinType` to faucet on `faucet` address, withdrawing funds from user balance. + public entry fun deposit(account: &signer, faucet_addr: address, amount: u64) acquires Faucet { + let coins = coin::withdraw(account, amount); + + deposit_internal(faucet_addr, coins); + } + + /// Deposits coins `CoinType` from faucet on user's account. + /// `faucet` - address of faucet to request funds. + public entry fun request(account: &signer, faucet_addr: address) acquires Faucet, Restricted { + let account_addr = signer::address_of(account); + + if (!coin::is_account_registered(account_addr)) { + coin::register(account); + }; + + let coins = request_internal(account, faucet_addr); + + coin::deposit(account_addr, coins); + } + + #[test_only] + use aptos_framework::genesis; + #[test_only] + use std::string::utf8; + #[test_only] + use aptos_framework::account::create_account; + + #[test_only] + struct FakeMoney has store {} + + #[test_only] + struct FakeMoneyCaps has key { + mint_cap: coin::MintCapability, + burn_cap: coin::BurnCapability, + } + + #[test(core = @core_resources, faucet_creator = @SwapDeployer, someone_else = @0x11)] + public entry fun test_faucet_end_to_end(core: &signer, faucet_creator: &signer, someone_else: &signer) acquires Faucet, Restricted { + genesis::setup(core); + + create_account(signer::address_of(faucet_creator)); + create_account(signer::address_of(someone_else)); + + let (m, b) = coin::initialize( + faucet_creator, + utf8(b"FakeMoney"), + utf8(b"FM"), + 8, + true + ); + + let amount = 100000000000000u64; + let per_request = 1000000000u64; + let period = 3000u64; + + let faucet_addr = signer::address_of(faucet_creator); + + let coins_minted = coin::mint(amount, &m); + coin::register(faucet_creator); + coin::deposit(faucet_addr, coins_minted); + + create_faucet(faucet_creator, amount / 2, per_request, period); + + request(faucet_creator, faucet_addr); + assert!(coin::balance(faucet_addr) == (amount / 2 + per_request), 0); + + let someone_else_addr = signer::address_of(someone_else); + request(someone_else, faucet_addr); + assert!(coin::balance(someone_else_addr) == per_request, 1); + + timestamp::update_global_time_for_test(3000000000); + + let new_per_request = 2000000000u64; + change_settings(faucet_creator, new_per_request, period); + + request(someone_else, faucet_addr); + assert!(coin::balance(someone_else_addr) == (per_request + new_per_request), 2); + + change_settings(faucet_creator, new_per_request, 5000); + let to_check = borrow_global>(faucet_addr); + assert!(to_check.period == 5000, 3); + assert!(to_check.per_request == new_per_request, 4); + + deposit(someone_else, faucet_addr, new_per_request); + assert!(coin::balance(someone_else_addr) == per_request, 5); + + move_to(faucet_creator, FakeMoneyCaps { + mint_cap: m, + burn_cap: b, + }); + } + + #[test(core = @core_resources, faucet_creator = @SwapDeployer, someone_else = @0x11)] + #[expected_failure(abort_code = 102)] + public entry fun test_faucet_fail_request(core: &signer, faucet_creator: &signer, someone_else: &signer) acquires Faucet, Restricted { + genesis::setup(core); + + create_account(signer::address_of(faucet_creator)); + create_account(signer::address_of(someone_else)); + + let (m, b) = coin::initialize( + faucet_creator, + utf8(b"FakeMoney"), + utf8(b"FM"), + 8, + true + ); + + let amount = 100000000000000u64; + let per_request = 1000000000u64; + let period = 3000u64; + + let faucet_addr = signer::address_of(faucet_creator); + + let coins_minted = coin::mint(amount, &m); + coin::register(faucet_creator); + coin::deposit(faucet_addr, coins_minted); + + create_faucet(faucet_creator, amount / 2, per_request, period); + + request(faucet_creator, faucet_addr); + request(faucet_creator, faucet_addr); + assert!(coin::balance(faucet_addr) == (amount / 2 + per_request), 0); + + move_to(faucet_creator, FakeMoneyCaps{ + mint_cap: m, + burn_cap: b, + }); + } + + #[test(core = @core_resources, faucet_creator = @SwapDeployer, someone_else = @0x11)] + #[expected_failure(abort_code = 101)] + public entry fun test_faucet_fail_settings(core: &signer, faucet_creator: &signer, someone_else: &signer) acquires Faucet { + genesis::setup(core); + + create_account(signer::address_of(faucet_creator)); + create_account(signer::address_of(someone_else)); + + let (m, b) = coin::initialize( + faucet_creator, + utf8(b"FakeMoney"), + utf8(b"FM"), + 8, + true + ); + + let amount = 100000000000000u64; + let per_request = 1000000000u64; + let period = 3000u64; + + let faucet_addr = signer::address_of(faucet_creator); + + let coins_minted = coin::mint(amount, &m); + coin::register(faucet_creator); + coin::deposit(faucet_addr, coins_minted); + + create_faucet(faucet_creator, amount / 2, per_request, period); + change_settings(someone_else, 1, 1); + + move_to(faucet_creator, FakeMoneyCaps{ + mint_cap: m, + burn_cap: b, + }); + } + + #[test(core = @core_resources, faucet_creator = @SwapDeployer, someone_else = @0x11)] + #[expected_failure(abort_code = 100)] + public entry fun test_already_exists(core: &signer, faucet_creator: &signer, someone_else: &signer) { + genesis::setup(core); + + create_account(signer::address_of(faucet_creator)); + create_account(signer::address_of(someone_else)); + + let (m, b) = coin::initialize( + faucet_creator, + utf8(b"FakeMoney"), + utf8(b"FM"), + 8, + true + ); + + let amount = 100000000000000u64; + let per_request = 1000000000u64; + let period = 3000u64; + + let faucet_addr = signer::address_of(faucet_creator); + + let coins_minted = coin::mint(amount, &m); + coin::register(faucet_creator); + coin::deposit(faucet_addr, coins_minted); + + create_faucet(faucet_creator, amount / 2, per_request, period); + create_faucet(faucet_creator, amount / 2, per_request, period); + + move_to(faucet_creator, FakeMoneyCaps{ + mint_cap: m, + burn_cap: b, + }); + } +} \ No newline at end of file diff --git a/networks/suzuka/suzuka-client/src/tests/hey-partners/LICENSE b/networks/suzuka/suzuka-client/src/tests/hey-partners/LICENSE new file mode 100644 index 000000000..f288702d2 --- /dev/null +++ b/networks/suzuka/suzuka-client/src/tests/hey-partners/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/networks/suzuka/suzuka-client/src/tests/hey-partners/LPCoin/Move.toml b/networks/suzuka/suzuka-client/src/tests/hey-partners/LPCoin/Move.toml new file mode 100644 index 000000000..10afede28 --- /dev/null +++ b/networks/suzuka/suzuka-client/src/tests/hey-partners/LPCoin/Move.toml @@ -0,0 +1,10 @@ +[package] +name = "LPCoin" +version = "0.3.0" + +[dependencies] +AptosFramework = { git = "https://github.com/aptos-labs/aptos-core.git", subdir = "aptos-move/framework/aptos-framework/", rev = "bbce0f188d7bef08218f1fc1f46bbd3676b5c74b" } + +[addresses] +ResourceAccountDeployer = "_" + diff --git a/networks/suzuka/suzuka-client/src/tests/hey-partners/LPCoin/sources/LPCoin.move b/networks/suzuka/suzuka-client/src/tests/hey-partners/LPCoin/sources/LPCoin.move new file mode 100644 index 000000000..ef12db308 --- /dev/null +++ b/networks/suzuka/suzuka-client/src/tests/hey-partners/LPCoin/sources/LPCoin.move @@ -0,0 +1,3 @@ +module ResourceAccountDeployer::LPCoinV1 { + struct LPCoin {} +} \ No newline at end of file diff --git a/networks/suzuka/suzuka-client/src/tests/hey-partners/LPResourceAccount/Move.toml b/networks/suzuka/suzuka-client/src/tests/hey-partners/LPResourceAccount/Move.toml new file mode 100644 index 000000000..b6b2fa765 --- /dev/null +++ b/networks/suzuka/suzuka-client/src/tests/hey-partners/LPResourceAccount/Move.toml @@ -0,0 +1,9 @@ +[package] +name = "LPResourceAccount" +version = "0.3.0" + +[dependencies] +AptosFramework = { git = "https://github.com/aptos-labs/aptos-core.git", subdir = "aptos-move/framework/aptos-framework/", rev = "bbce0f188d7bef08218f1fc1f46bbd3676b5c74b" } + +[addresses] +SwapDeployer = "_" diff --git a/networks/suzuka/suzuka-client/src/tests/hey-partners/LPResourceAccount/sources/resourceAccount.move b/networks/suzuka/suzuka-client/src/tests/hey-partners/LPResourceAccount/sources/resourceAccount.move new file mode 100644 index 000000000..e256d2ab0 --- /dev/null +++ b/networks/suzuka/suzuka-client/src/tests/hey-partners/LPResourceAccount/sources/resourceAccount.move @@ -0,0 +1,38 @@ +/// The module used to create user resource account for swap and deploy LP coins under that account. +module SwapDeployer::LPResourceAccount { + use std::signer; + + use aptos_framework::account::{Self, SignerCapability}; + + /// When called from wrong account. + const ERR_FORBIDDEN: u64 = 103; + + /// Temporary storage for user resource account signer capability. + struct CapabilityStorage has key { signer_cap: SignerCapability } + + /// Creates new resource account for swap, puts signer capability into storage and deploys LP coin type. + /// Can be executed only from swap account. + public entry fun initialize_lp_account( + admin: &signer, + lp_coin_metadata_serialized: vector, + lp_coin_code: vector + ) { + assert!(signer::address_of(admin) == @SwapDeployer, ERR_FORBIDDEN); + + let (lp_acc, signer_cap) = account::create_resource_account(admin, x"30"); + aptos_framework::code::publish_package_txn( + &lp_acc, + lp_coin_metadata_serialized, + vector[lp_coin_code] + ); + move_to(admin, CapabilityStorage { signer_cap }); + } + + /// Destroys temporary storage for resource account signer capability and returns signer capability. + /// It needs for initialization of swap. + public fun retrieve_signer_cap(admin: &signer): SignerCapability acquires CapabilityStorage { + assert!(signer::address_of(admin) == @SwapDeployer, ERR_FORBIDDEN); + let CapabilityStorage { signer_cap } = move_from(signer::address_of(admin)); + signer_cap + } +} diff --git a/networks/suzuka/suzuka-client/src/tests/hey-partners/README.md b/networks/suzuka/suzuka-client/src/tests/hey-partners/README.md new file mode 100644 index 000000000..89300b0c3 --- /dev/null +++ b/networks/suzuka/suzuka-client/src/tests/hey-partners/README.md @@ -0,0 +1,124 @@ +# MovementSwap + +**MovementSwap** is AMM protocol for [Aptos](https://www.aptos.com/) blockchain. It's a fork of [AnimeSwap](https://animeswap.org). + +* [Contracts documents](https://docs.animeswap.org/docs/contracts/Aptos/contracts) +* [SDK](https://github.com/AnimeSwap/v1-sdk) + +The current repository contains: + +* u256 +* uq64x64 +* TestCoin +* Faucet +* LPCoin +* LPResourceAccount +* Swap + +## Add as dependency + +Update your `Move.toml` with + +```toml +[dependencies.AnimeSwap] +git = 'https://github.com/AnimeSwap/v1-core.git' +rev = 'v1.0.1' +subdir = 'Swap' +``` + +----- + +Swap example: + +```move +// swap exact coin to maximal coin +use SwapDeployer::AnimeSwapPoolV1; +... +// swap `amount_in` X to Y +let amount_in = 100000; +let coins_in = coin::withdraw(&account, amount_in); +let coins_out = AnimeSwapPoolV1::swap_coins_for_coins(coins_in); +``` + +or + +```move +// swap minimal coin to exact coin (maybe some more dust) +use SwapDeployer::AnimeSwapPoolV1; +... +// swap X to `amount_out` Y +let amount_out = 100000; +let amount_in = AnimeSwapPoolV1::get_amounts_in_1_pair(amount_out); +// check if `amount_in` meets your demand +let coins_in = coin::withdraw(&account, amount_in); +let coins_out = AnimeSwapPoolV1::swap_coins_for_coins(coins_in); +// Because of discrete, coins_out value is actually `amount_out + dust`. +// Our protocol does not keep the dust, but return to user instead. +assert!(coin::value(&coins_out) >= amount_out, 1); +``` + +----- + +Flash swap example: + +```move +use SwapDeployer::AnimeSwapPoolV1Library; +use SwapDeployer::AnimeSwapPoolV1; +... +// loan `amount` Y and repay X +let amount = 100000; +let borrow_amount = AnimeSwapPoolV1::get_amounts_out_1_pair(amount); +let coins_out; +if (AnimeSwapPoolV1Library::compare()) { + // flash loan Y + let (coins_in_zero, coins_in, flash_swap) = AnimeSwapPoolV1::flash_swap(0, borrow_amount); + coin::destroy_zero(coins_in_zero); + // do something with coins_in and get coins_out + coins_out = f(coins_in); + // repay X + let repay_coins = coin::extract(&mut coins_out, amount); + AnimeSwapPoolV1::pay_flash_swap(repay_coins, coin::zero(), flash_swap); +} else { + // flash loan Y + let (coins_in, coins_in_zero, flash_swap) = AnimeSwapPoolV1::flash_swap(borrow_amount, 0); + coin::destroy_zero(coins_in_zero); + // do something with coins_in and get coins_out + coins_out = f(coins_in); + // repay X + let repay_coins = coin::extract(&mut coins_out, amount); + AnimeSwapPoolV1::pay_flash_swap(coin::zero(), repay_coins, flash_swap); +}; +// keep the rest `coins_out` +``` + +or + +```move +use SwapDeployer::AnimeSwapPoolV1Library; +use SwapDeployer::AnimeSwapPoolV1; +... +// loan `amount` X and repay Y +let amount = 100000; +let repay_amount = AnimeSwapPoolV1::get_amounts_in_1_pair(amount); +let coins_out; +if (AnimeSwapPoolV1Library::compare()) { + // flash loan X + let (coins_in, coins_in_zero, flash_swap) = AnimeSwapPoolV1::flash_swap(amount, 0); + coin::destroy_zero(coins_in_zero); + // do something with coins_in and get coins_out + coins_out = f(coins_in); + // repay Y + let repay_coins = coin::extract(&mut coins_out, repay_amount); + AnimeSwapPoolV1::pay_flash_swap(coin::zero(), repay_coins, flash_swap); +} else { + // flash loan X + let (coins_in_zero, coins_in, flash_swap) = AnimeSwapPoolV1::flash_swap(0, amount); + coin::destroy_zero(coins_in_zero); + // do something with coins_in and get coins_out + coins_out = f(coins_in); + // repay Y + let repay_coins = coin::extract(&mut coins_out, repay_amount); + AnimeSwapPoolV1::pay_flash_swap(repay_coins, coin::zero(), flash_swap); +}; +// keep the rest `coins_out` +``` diff --git a/networks/suzuka/suzuka-client/src/tests/hey-partners/Swap/Move.toml b/networks/suzuka/suzuka-client/src/tests/hey-partners/Swap/Move.toml new file mode 100644 index 000000000..0f2281d6f --- /dev/null +++ b/networks/suzuka/suzuka-client/src/tests/hey-partners/Swap/Move.toml @@ -0,0 +1,14 @@ +[package] +name = "AnimeSwapV1" +version = "1.0.1" + +[dependencies] +AptosFramework = { git = "https://github.com/aptos-labs/aptos-core.git", subdir = "aptos-move/framework/aptos-framework/", rev = "bbce0f188d7bef08218f1fc1f46bbd3676b5c74b" } +LPCoin = { local = "../LPCoin" } +LPResourceAccount = { local = "../LPResourceAccount" } +U256 = { local = "../u256" } +UQ64x64 = { local = "../uq64x64" } + +[addresses] +SwapDeployer = "_" +ResourceAccountDeployer = "_" diff --git a/networks/suzuka/suzuka-client/src/tests/hey-partners/Swap/sources/swap.move b/networks/suzuka/suzuka-client/src/tests/hey-partners/Swap/sources/swap.move new file mode 100644 index 000000000..cb1449eab --- /dev/null +++ b/networks/suzuka/suzuka-client/src/tests/hey-partners/Swap/sources/swap.move @@ -0,0 +1,1811 @@ +module SwapDeployer::AnimeSwapPoolV1 { + use ResourceAccountDeployer::LPCoinV1::LPCoin; + use SwapDeployer::AnimeSwapPoolV1Library; + use SwapDeployer::LPResourceAccount; + use std::signer; + use std::type_info::{Self, TypeInfo}; + use std::string::utf8; + use std::event; + use std::vector; + use aptos_framework::timestamp; + use aptos_framework::coin::{Self, Coin, MintCapability, FreezeCapability, BurnCapability}; + use aptos_framework::account::{Self, SignerCapability}; + use u256::u256; + use uq64x64::uq64x64; + use std::debug; // For debug + + /// pool data + struct LiquidityPool has key { + coin_x_reserve: Coin, + coin_y_reserve: Coin, + last_block_timestamp: u64, + last_price_x_cumulative: u128, + last_price_y_cumulative: u128, + k_last: u128, + lp_mint_cap: MintCapability>, + lp_freeze_cap: FreezeCapability>, + lp_burn_cap: BurnCapability>, + locked: bool, + } + + /// global config data + struct AdminData has key { + signer_cap: SignerCapability, + dao_fee_to: address, + admin_address: address, + dao_fee: u8, // 1/(dao_fee+1) comes to dao_fee_to if dao_fee_on + swap_fee: u64, // BP, swap_fee * 1/10000 + dao_fee_on: bool, // default: true + is_pause: bool, // pause swap + } + + struct PairMeta has drop, store, copy { + coin_x: TypeInfo, + coin_y: TypeInfo, + lp_coin: TypeInfo, + } + + /// pair list + struct PairInfo has key { + pair_list: vector, + } + + struct Events has key { + pair_created_event: event::EventHandle>, + mint_event: event::EventHandle>, + burn_event: event::EventHandle>, + swap_event: event::EventHandle>, + sync_event: event::EventHandle>, + flash_swap_event: event::EventHandle>, + } + + struct PairCreatedEvent has drop, store { + meta: PairMeta, + } + + struct MintEvent has drop, store { + amount_x: u64, + amount_y: u64, + liquidity: u64, + } + + struct BurnEvent has drop, store { + amount_x: u64, + amount_y: u64, + liquidity: u64, + } + + struct SwapEvent has drop, store { + amount_x_in: u64, + amount_y_in: u64, + amount_x_out: u64, + amount_y_out: u64, + } + + struct SyncEvent has drop, store { + reserve_x: u64, + reserve_y: u64, + last_price_x_cumulative: u128, + last_price_y_cumulative: u128, + } + + struct FlashSwapEvent has drop, store { + loan_coin_x: u64, + loan_coin_y: u64, + repay_coin_x: u64, + repay_coin_y: u64, + } + + /// no copy, no drop + struct FlashSwap { + loan_coin_x: u64, + loan_coin_y: u64 + } + + const MINIMUM_LIQUIDITY: u64 = 1000; + const MAX_U64: u64 = 18446744073709551615u64; + + /// When contract error + const ERR_INTERNAL_ERROR: u64 = 102; + /// When user is not admin + const ERR_FORBIDDEN: u64 = 103; + /// When not enough amount for pool + const ERR_INSUFFICIENT_AMOUNT: u64 = 104; + /// When not enough liquidity amount + const ERR_INSUFFICIENT_LIQUIDITY: u64 = 105; + /// When not enough liquidity minted + const ERR_INSUFFICIENT_LIQUIDITY_MINT: u64 = 106; + /// When not enough liquidity burned + const ERR_INSUFFICIENT_LIQUIDITY_BURN: u64 = 107; + /// When not enough X amount + const ERR_INSUFFICIENT_X_AMOUNT: u64 = 108; + /// When not enough Y amount + const ERR_INSUFFICIENT_Y_AMOUNT: u64 = 109; + /// When not enough input amount + const ERR_INSUFFICIENT_INPUT_AMOUNT: u64 = 110; + /// When not enough output amount + const ERR_INSUFFICIENT_OUTPUT_AMOUNT: u64 = 111; + /// When contract K error + const ERR_K_ERROR: u64 = 112; + /// When already exists on account + const ERR_PAIR_ALREADY_EXIST: u64 = 115; + /// When not exists on account + const ERR_PAIR_NOT_EXIST: u64 = 116; + /// When error loan amount + const ERR_LOAN_ERROR: u64 = 117; + /// When contract is not reentrant + const ERR_LOCK_ERROR: u64 = 118; + /// When pair has wrong ordering + const ERR_PAIR_ORDER_ERROR: u64 = 119; + /// When contract is paused + const ERR_PAUSABLE_ERROR: u64 = 120; + + const DEPLOYER_ADDRESS: address = @SwapDeployer; + const RESOURCE_ACCOUNT_ADDRESS: address = @ResourceAccountDeployer; + + // initialize + fun init_module(admin: &signer) { + // init admin data + let signer_cap = LPResourceAccount::retrieve_signer_cap(admin); + let resource_account = &account::create_signer_with_capability(&signer_cap); + move_to(resource_account, AdminData { + signer_cap, + dao_fee_to: DEPLOYER_ADDRESS, + admin_address: DEPLOYER_ADDRESS, + dao_fee: 5, // 1/6 to dao fee + swap_fee: 30, // 0.3% + dao_fee_on: true, // default true + is_pause: false, // default false + }); + // init pair info + move_to(resource_account, PairInfo{ + pair_list: vector::empty(), + }); + } + + /** + * Helper functions, for internal use. Some are public for helping other contracts calculation + */ + + /// get reserves size + /// always return (X_reserve, Y_reserve) + public fun get_reserves_size(): (u64, u64) acquires LiquidityPool { + if (AnimeSwapPoolV1Library::compare()) { + let lp = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + (coin::value(&lp.coin_x_reserve), coin::value(&lp.coin_y_reserve)) + } else { + let lp = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + (coin::value(&lp.coin_y_reserve), coin::value(&lp.coin_x_reserve)) + } + } + + /// get amounts out, 1 pair + public fun get_amounts_out_1_pair( + amount_in: u64 + ): u64 acquires LiquidityPool, AdminData { + let swap_fee = borrow_global(RESOURCE_ACCOUNT_ADDRESS).swap_fee; + let (reserve_in, reserve_out) = get_reserves_size(); + let amount_out = AnimeSwapPoolV1Library::get_amount_out(amount_in, reserve_in, reserve_out, swap_fee); + amount_out + } + + /// get amounts out, 2 pairs + public fun get_amounts_out_2_pair( + amount_in: u64 + ): u64 acquires LiquidityPool, AdminData { + let swap_fee = borrow_global(RESOURCE_ACCOUNT_ADDRESS).swap_fee; + let (reserve_in, reserve_out) = get_reserves_size(); + let amount_mid = AnimeSwapPoolV1Library::get_amount_out(amount_in, reserve_in, reserve_out, swap_fee); + (reserve_in, reserve_out) = get_reserves_size(); + let amount_out = AnimeSwapPoolV1Library::get_amount_out(amount_mid, reserve_in, reserve_out, swap_fee); + amount_out + } + + /// get amounts out, 3 pairs + public fun get_amounts_out_3_pair( + amount_in: u64 + ): u64 acquires LiquidityPool, AdminData { + let swap_fee = borrow_global(RESOURCE_ACCOUNT_ADDRESS).swap_fee; + let (reserve_in, reserve_out) = get_reserves_size(); + let amount_mid = AnimeSwapPoolV1Library::get_amount_out(amount_in, reserve_in, reserve_out, swap_fee); + (reserve_in, reserve_out) = get_reserves_size(); + let amount_mid = AnimeSwapPoolV1Library::get_amount_out(amount_mid, reserve_in, reserve_out, swap_fee); + (reserve_in, reserve_out) = get_reserves_size(); + let amount_out = AnimeSwapPoolV1Library::get_amount_out(amount_mid, reserve_in, reserve_out, swap_fee); + amount_out + } + + /// get amounts in, 1 pair + public fun get_amounts_in_1_pair( + amount_out: u64 + ): u64 acquires LiquidityPool, AdminData { + let swap_fee = borrow_global(RESOURCE_ACCOUNT_ADDRESS).swap_fee; + let (reserve_in, reserve_out) = get_reserves_size(); + let amount_in = AnimeSwapPoolV1Library::get_amount_in(amount_out, reserve_in, reserve_out, swap_fee); + amount_in + } + + /// get amounts in, 2 pairs + public fun get_amounts_in_2_pair( + amount_out: u64 + ): u64 acquires LiquidityPool, AdminData { + let swap_fee = borrow_global(RESOURCE_ACCOUNT_ADDRESS).swap_fee; + let (reserve_in, reserve_out) = get_reserves_size(); + let amount_mid = AnimeSwapPoolV1Library::get_amount_in(amount_out, reserve_in, reserve_out, swap_fee); + (reserve_in, reserve_out) = get_reserves_size(); + let amount_in = AnimeSwapPoolV1Library::get_amount_in(amount_mid, reserve_in, reserve_out, swap_fee); + amount_in + } + + /// get amounts in, 3 pairs + public fun get_amounts_in_3_pair( + amount_out: u64 + ): u64 acquires LiquidityPool, AdminData { + let swap_fee = borrow_global(RESOURCE_ACCOUNT_ADDRESS).swap_fee; + let (reserve_in, reserve_out) = get_reserves_size(); + let amount_mid = AnimeSwapPoolV1Library::get_amount_in(amount_out, reserve_in, reserve_out, swap_fee); + (reserve_in, reserve_out) = get_reserves_size(); + let amount_mid = AnimeSwapPoolV1Library::get_amount_in(amount_mid, reserve_in, reserve_out, swap_fee); + (reserve_in, reserve_out) = get_reserves_size(); + let amount_in = AnimeSwapPoolV1Library::get_amount_in(amount_mid, reserve_in, reserve_out, swap_fee); + amount_in + } + + /// get pair meta with `X`, `Y` + public fun get_pair_meta(): PairMeta { + let coin_x_type_info = type_info::type_of(); + let coin_y_type_info = type_info::type_of(); + let lp_coin_type_info = type_info::type_of>(); + PairMeta { + coin_x: coin_x_type_info, + coin_y: coin_y_type_info, + lp_coin: lp_coin_type_info, + } + } + + /// assert lp unlocked + fun assert_lp_unlocked() acquires LiquidityPool { + assert!(exists>(RESOURCE_ACCOUNT_ADDRESS), ERR_PAIR_NOT_EXIST); + let lp = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + assert!(lp.locked == false, ERR_LOCK_ERROR); + } + + /// assert swap paused + fun assert_paused() acquires AdminData { + assert!(borrow_global(RESOURCE_ACCOUNT_ADDRESS).is_pause, ERR_PAUSABLE_ERROR); + } + + /// assert swap not paused + fun assert_not_paused() acquires AdminData { + assert!(!borrow_global(RESOURCE_ACCOUNT_ADDRESS).is_pause, ERR_PAUSABLE_ERROR); + } + + /// return pair admin account signer + fun get_resource_account_signer(): signer acquires AdminData { + let signer_cap = &borrow_global(RESOURCE_ACCOUNT_ADDRESS).signer_cap; + account::create_signer_with_capability(signer_cap) + } + + /// Calculate optimal amounts of coins to add + public fun calc_optimal_coin_values( + amount_x_desired: u64, + amount_y_desired: u64, + amount_x_min: u64, + amount_y_min: u64 + ): (u64, u64) acquires LiquidityPool { + let lp = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + let (reserve_x, reserve_y) = (coin::value(&lp.coin_x_reserve), coin::value(&lp.coin_y_reserve)); + if (reserve_x == 0 && reserve_y == 0) { + (amount_x_desired, amount_y_desired) + } else { + let amount_y_optimal = AnimeSwapPoolV1Library::quote(amount_x_desired, reserve_x, reserve_y); + if (amount_y_optimal <= amount_y_desired) { + assert!(amount_y_optimal >= amount_y_min, ERR_INSUFFICIENT_Y_AMOUNT); + (amount_x_desired, amount_y_optimal) + } else { + let amount_x_optimal = AnimeSwapPoolV1Library::quote(amount_y_desired, reserve_y, reserve_x); + assert!(amount_x_optimal <= amount_x_desired, ERR_INTERNAL_ERROR); + assert!(amount_x_optimal >= amount_x_min, ERR_INSUFFICIENT_X_AMOUNT); + (amount_x_optimal, amount_y_desired) + } + } + } + + /// k should not decrease + fun assert_k_increase( + balance_x: u64, + balance_y: u64, + amount_x_in: u64, + amount_y_in: u64, + reserve_x: u64, + reserve_y: u64, + ) acquires AdminData { + let swap_fee = borrow_global(RESOURCE_ACCOUNT_ADDRESS).swap_fee; + let balance_x_adjusted = (balance_x as u128) * 10000 - (amount_x_in as u128) * (swap_fee as u128); + let balance_y_adjusted = (balance_y as u128) * 10000 - (amount_y_in as u128) * (swap_fee as u128); + let balance_xy_old_not_scaled = (reserve_x as u128) * (reserve_y as u128); + let scale = 100000000; + // should be: new_reserve_x * new_reserve_y > old_reserve_x * old_eserve_y + // gas saving + if ( + AnimeSwapPoolV1Library::is_overflow_mul(balance_x_adjusted, balance_y_adjusted) + || AnimeSwapPoolV1Library::is_overflow_mul(balance_xy_old_not_scaled, scale) + ) { + let balance_xy_adjusted = u256::mul(u256::from_u128(balance_x_adjusted), u256::from_u128(balance_y_adjusted)); + let balance_xy_old = u256::mul(u256::from_u128(balance_xy_old_not_scaled), u256::from_u128(scale)); + assert!(u256::compare(&balance_xy_adjusted, &balance_xy_old) == 2, ERR_K_ERROR); + } else { + assert!(balance_x_adjusted * balance_y_adjusted >= balance_xy_old_not_scaled * scale, ERR_K_ERROR) + }; + } + + /// update cumulative, coin_reserve, block_timestamp + fun update_internal( + lp: &mut LiquidityPool, + balance_x: u64, // new reserve value + balance_y: u64, + reserve_x: u64, // old reserve value + reserve_y: u64 + ) acquires Events { + let now = timestamp::now_seconds(); + let time_elapsed = ((now - lp.last_block_timestamp) as u128); + if (time_elapsed > 0 && reserve_x != 0 && reserve_y != 0) { + // allow overflow u128 + let last_price_x_cumulative_delta = uq64x64::to_u128(uq64x64::fraction(reserve_y, reserve_x)) * time_elapsed; + lp.last_price_x_cumulative = AnimeSwapPoolV1Library::overflow_add(lp.last_price_x_cumulative, last_price_x_cumulative_delta); + + let last_price_y_cumulative_delta = uq64x64::to_u128(uq64x64::fraction(reserve_x, reserve_y)) * time_elapsed; + lp.last_price_y_cumulative = AnimeSwapPoolV1Library::overflow_add(lp.last_price_y_cumulative, last_price_y_cumulative_delta); + }; + lp.last_block_timestamp = now; + // event + let events = borrow_global_mut>(RESOURCE_ACCOUNT_ADDRESS); + event::emit_event(&mut events.sync_event, SyncEvent { + reserve_x: balance_x, + reserve_y: balance_y, + last_price_x_cumulative: lp.last_price_x_cumulative, + last_price_y_cumulative: lp.last_price_y_cumulative, + }); + } + + fun mint_fee_interval( + lp: &mut LiquidityPool, + admin_data: &AdminData + ): bool { + let fee_on = admin_data.dao_fee_on; + let k_last = lp.k_last; + if (fee_on) { + if (k_last != 0) { + let reserve_x = coin::value(&lp.coin_x_reserve); + let reserve_y = coin::value(&lp.coin_y_reserve); + let root_k = AnimeSwapPoolV1Library::sqrt(reserve_x, reserve_y); + let root_k_last = AnimeSwapPoolV1Library::sqrt_128(k_last); + let total_supply = AnimeSwapPoolV1Library::get_lpcoin_total_supply>(); + if (root_k > root_k_last) { + let delta_k = ((root_k - root_k_last) as u128); + // gas saving + if (AnimeSwapPoolV1Library::is_overflow_mul(total_supply, delta_k)) { + let numerator = u256::mul(u256::from_u128(total_supply), u256::from_u128(delta_k)); + let denominator = u256::from_u128((root_k as u128) * (admin_data.dao_fee as u128) + (root_k_last as u128)); + let liquidity = u256::as_u64(u256::div(numerator, denominator)); + if (liquidity > 0) { + mint_coin(&account::create_signer_with_capability(&admin_data.signer_cap), liquidity, &lp.lp_mint_cap); + }; + } else { + let numerator = total_supply * delta_k; + let denominator = (root_k as u128) * (admin_data.dao_fee as u128) + (root_k_last as u128); + let liquidity = ((numerator / denominator) as u64); + if (liquidity > 0) { + mint_coin(&account::create_signer_with_capability(&admin_data.signer_cap), liquidity, &lp.lp_mint_cap); + }; + }; + } + } + } else if (k_last != 0) { + lp.k_last = 0; + }; + fee_on + } + + /// mint coin with MintCapability + fun mint_coin( + account: &signer, + amount: u64, + mint_cap: &MintCapability> + ) { + let acc_addr = signer::address_of(account); + if (!coin::is_account_registered>(acc_addr)) { + coin::register>(account); + }; + let coins = coin::mint>(amount, mint_cap); + coin::deposit(acc_addr, coins); + } + + /** + * Entry functions + */ + + /// Add liquidity. If pair not exist, create pair first + /// No require for pair order sorting + public entry fun add_liquidity_entry( + account: &signer, + amount_x_desired: u64, + amount_y_desired: u64, + amount_x_min: u64, + amount_y_min: u64, + ) acquires LiquidityPool, AdminData, PairInfo, Events { + if (AnimeSwapPoolV1Library::compare()) { + if (!exists>(RESOURCE_ACCOUNT_ADDRESS)) { + create_pair(); + }; + add_liquidity(account, amount_x_desired, amount_y_desired, amount_x_min, amount_y_min); + } else { + if (!exists>(RESOURCE_ACCOUNT_ADDRESS)) { + create_pair(); + }; + add_liquidity(account, amount_y_desired, amount_x_desired, amount_y_min, amount_x_min); + } + } + + /// Remove liquidity + /// No require for pair order sorting + public entry fun remove_liquidity_entry( + account: &signer, + liquidity: u64, + amount_x_min: u64, + amount_y_min: u64, + ) acquires LiquidityPool, AdminData, Events { + let (x_out, y_out); + if (AnimeSwapPoolV1Library::compare()) { + let coins = coin::withdraw>(account, liquidity); + (x_out, y_out) = remove_liquidity(coins, amount_x_min, amount_y_min); + } else { + let coins = coin::withdraw>(account, liquidity); + (y_out, x_out) = remove_liquidity(coins, amount_y_min, amount_x_min); + }; + // transfer + let account_addr = signer::address_of(account); + coin::deposit(account_addr, x_out); + coin::deposit(account_addr, y_out); + } + + /// 1 pair swap X->Y + public entry fun swap_exact_coins_for_coins_entry( + account: &signer, + amount_in: u64, + amount_out_min: u64, + ) acquires LiquidityPool, AdminData, Events { + // swap + let coins_in = coin::withdraw(account, amount_in); + let coins_out; + coins_out = swap_coins_for_coins(coins_in); + assert!(coin::value(&coins_out) >= amount_out_min, ERR_INSUFFICIENT_OUTPUT_AMOUNT); + AnimeSwapPoolV1Library::register_coin(account); + coin::deposit(signer::address_of(account), coins_out); + } + + /// 2 pairs swap X->Y->Z + public entry fun swap_exact_coins_for_coins_2_pair_entry( + account: &signer, + amount_in: u64, + amount_out_min: u64, + ) acquires LiquidityPool, AdminData, Events { + // swap + let coins_in = coin::withdraw(account, amount_in); + let coins_out; + let coins_mid; + coins_mid = swap_coins_for_coins(coins_in); + coins_out = swap_coins_for_coins(coins_mid); + assert!(coin::value(&coins_out) >= amount_out_min, ERR_INSUFFICIENT_OUTPUT_AMOUNT); + AnimeSwapPoolV1Library::register_coin(account); + coin::deposit(signer::address_of(account), coins_out); + } + + /// 3 pairs swap X->Y->Z->W + public entry fun swap_exact_coins_for_coins_3_pair_entry( + account: &signer, + amount_in: u64, + amount_out_min: u64, + ) acquires LiquidityPool, AdminData, Events { + // swap + let coins_in = coin::withdraw(account, amount_in); + let coins_out; + let coins_mid; + let coins_mid_2; + coins_mid = swap_coins_for_coins(coins_in); + coins_mid_2 = swap_coins_for_coins(coins_mid); + coins_out = swap_coins_for_coins(coins_mid_2); + assert!(coin::value(&coins_out) >= amount_out_min, ERR_INSUFFICIENT_OUTPUT_AMOUNT); + AnimeSwapPoolV1Library::register_coin(account); + coin::deposit(signer::address_of(account), coins_out); + } + + /// 1 pair swap X->Y + public entry fun swap_coins_for_exact_coins_entry( + account: &signer, + amount_out: u64, + amount_in_max: u64, + ) acquires LiquidityPool, AdminData, Events { + let amount_in = get_amounts_in_1_pair(amount_out); + assert!(amount_in <= amount_in_max, ERR_INSUFFICIENT_INPUT_AMOUNT); + let coins_in = coin::withdraw(account, amount_in); + let coins_out; + coins_out = swap_coins_for_coins(coins_in); + AnimeSwapPoolV1Library::register_coin(account); + coin::deposit(signer::address_of(account), coins_out); + } + + /// 2 pairs swap X->Y->Z + public entry fun swap_coins_for_exact_coins_2_pair_entry( + account: &signer, + amount_out: u64, + amount_in_max: u64, + ) acquires LiquidityPool, AdminData, Events { + let amount_in = get_amounts_in_2_pair(amount_out); + assert!(amount_in <= amount_in_max, ERR_INSUFFICIENT_INPUT_AMOUNT); + // swap + let coins_in = coin::withdraw(account, amount_in); + let coins_out; + let coins_mid; + coins_mid = swap_coins_for_coins(coins_in); + coins_out = swap_coins_for_coins(coins_mid); + AnimeSwapPoolV1Library::register_coin(account); + coin::deposit(signer::address_of(account), coins_out); + } + + /// 3 pairs swap X->Y->Z->W + public entry fun swap_coins_for_exact_coins_3_pair_entry( + account: &signer, + amount_out: u64, + amount_in_max: u64, + ) acquires LiquidityPool, AdminData, Events { + let amount_in = get_amounts_in_3_pair(amount_out); + assert!(amount_in <= amount_in_max, ERR_INSUFFICIENT_INPUT_AMOUNT); + // swap + let coins_in = coin::withdraw(account, amount_in); + let coins_out; + let coins_mid; + let coins_mid_2; + coins_mid = swap_coins_for_coins(coins_in); + coins_mid_2 = swap_coins_for_coins(coins_mid); + coins_out = swap_coins_for_coins(coins_mid_2); + AnimeSwapPoolV1Library::register_coin(account); + coin::deposit(signer::address_of(account), coins_out); + } + + /** + * Setting config functions + */ + + public entry fun set_dao_fee_to( + account: &signer, + dao_fee_to: address + ) acquires AdminData { + let admin_data = borrow_global_mut(RESOURCE_ACCOUNT_ADDRESS); + assert!(signer::address_of(account) == admin_data.admin_address, ERR_FORBIDDEN); + admin_data.dao_fee_to = dao_fee_to; + } + + public entry fun set_admin_address( + account: &signer, + admin_address: address + ) acquires AdminData { + let admin_data = borrow_global_mut(RESOURCE_ACCOUNT_ADDRESS); + assert!(signer::address_of(account) == admin_data.admin_address, ERR_FORBIDDEN); + admin_data.admin_address = admin_address; + } + + public entry fun set_dao_fee( + account: &signer, + dao_fee: u8 + ) acquires AdminData { + let admin_data = borrow_global_mut(RESOURCE_ACCOUNT_ADDRESS); + assert!(signer::address_of(account) == admin_data.admin_address, ERR_FORBIDDEN); + if (dao_fee == 0) { + admin_data.dao_fee_on = false; + } else { + admin_data.dao_fee_on = true; + admin_data.dao_fee = dao_fee; + }; + } + + public entry fun set_swap_fee( + account: &signer, + swap_fee: u64 + ) acquires AdminData { + let admin_data = borrow_global_mut(RESOURCE_ACCOUNT_ADDRESS); + assert!(signer::address_of(account) == admin_data.admin_address, ERR_FORBIDDEN); + assert!(swap_fee <= 1000, ERR_FORBIDDEN); + admin_data.swap_fee = swap_fee; + } + + public entry fun withdraw_dao_fee( + account: &signer + ) acquires AdminData { + if (!AnimeSwapPoolV1Library::compare()) { + withdraw_dao_fee(account); + return + }; + let admin_data = borrow_global(RESOURCE_ACCOUNT_ADDRESS); + let acc_addr = signer::address_of(account); + assert!(acc_addr == admin_data.dao_fee_to, ERR_FORBIDDEN); + if (!coin::is_account_registered>(acc_addr)) { + coin::register>(account); + }; + let amount = coin::balance>(RESOURCE_ACCOUNT_ADDRESS) - MINIMUM_LIQUIDITY; + coin::transfer>(&get_resource_account_signer(), acc_addr, amount); + } + + /// pause swap, only remove lp is allowed + /// EMERGENCY ONLY + public entry fun pause( + account: &signer + ) acquires AdminData { + assert_not_paused(); + let admin_data = borrow_global_mut(RESOURCE_ACCOUNT_ADDRESS); + assert!(signer::address_of(account) == admin_data.admin_address, ERR_FORBIDDEN); + admin_data.is_pause = true; + } + + /// unpause swap + /// EMERGENCY ONLY + public entry fun unpause( + account: &signer + ) acquires AdminData { + assert_paused(); + let admin_data = borrow_global_mut(RESOURCE_ACCOUNT_ADDRESS); + assert!(signer::address_of(account) == admin_data.admin_address, ERR_FORBIDDEN); + admin_data.is_pause = false; + } + + /** + * Router functions, can be called by other contracts + */ + + /// Create pair, and register events + /// require X < Y + public fun create_pair() acquires AdminData, PairInfo { + assert!(AnimeSwapPoolV1Library::compare(), ERR_PAIR_ORDER_ERROR); + assert!(!exists>(RESOURCE_ACCOUNT_ADDRESS), ERR_PAIR_ALREADY_EXIST); + assert_not_paused(); + let resource_account_signer = get_resource_account_signer(); + // create lp coin + let (lp_b, lp_f, lp_m) = coin::initialize>(&resource_account_signer, utf8(b"AnimeSwapLPCoin"), utf8(b"ANILPCoin"), 8, true); + // register coin + AnimeSwapPoolV1Library::register_coin>(&resource_account_signer); + // register LiquidityPool + move_to(&resource_account_signer, LiquidityPool{ + coin_x_reserve: coin::zero(), + coin_y_reserve: coin::zero(), + last_block_timestamp: 0, + last_price_x_cumulative: 0, + last_price_y_cumulative: 0, + k_last: 0, + lp_mint_cap: lp_m, + lp_freeze_cap: lp_f, + lp_burn_cap: lp_b, + locked: false, + }); + // add pair_info + let pair_meta = get_pair_meta(); + let pair_info = borrow_global_mut(RESOURCE_ACCOUNT_ADDRESS); + vector::push_back(&mut pair_info.pair_list, copy pair_meta); + + // init events + let events = Events { + pair_created_event: account::new_event_handle>(&resource_account_signer), + mint_event: account::new_event_handle>(&resource_account_signer), + burn_event: account::new_event_handle>(&resource_account_signer), + swap_event: account::new_event_handle>(&resource_account_signer), + sync_event: account::new_event_handle>(&resource_account_signer), + flash_swap_event: account::new_event_handle>(&resource_account_signer), + }; + event::emit_event(&mut events.pair_created_event, PairCreatedEvent { + meta: pair_meta, + }); + move_to(&resource_account_signer, events); + } + + /// Add liquidity + /// require X < Y + public fun add_liquidity( + account: &signer, + amount_x_desired: u64, + amount_y_desired: u64, + amount_x_min: u64, + amount_y_min: u64, + ) acquires LiquidityPool, AdminData, Events { + // check lp exist + assert!(AnimeSwapPoolV1Library::compare(), ERR_PAIR_ORDER_ERROR); + assert!(exists>(RESOURCE_ACCOUNT_ADDRESS), ERR_PAIR_NOT_EXIST); + let (amount_x, amount_y) = calc_optimal_coin_values(amount_x_desired, amount_y_desired, amount_x_min, amount_y_min); + let coin_x = coin::withdraw(account, amount_x); + let coin_y = coin::withdraw(account, amount_y); + let lp_coins = mint(coin_x, coin_y); + + let acc_addr = signer::address_of(account); + if (!coin::is_account_registered>(acc_addr)) { + coin::register>(account); + }; + coin::deposit(acc_addr, lp_coins); + } + + /// Remove liquidity + /// require X < Y + public fun remove_liquidity( + coins: Coin>, + amount_x_min: u64, + amount_y_min: u64, + ): (Coin, Coin) acquires LiquidityPool, AdminData, Events { + assert!(AnimeSwapPoolV1Library::compare(), ERR_PAIR_ORDER_ERROR); + let (x_out, y_out) = burn(coins); + assert!(coin::value(&x_out) >= amount_x_min, ERR_INSUFFICIENT_X_AMOUNT); + assert!(coin::value(&y_out) >= amount_y_min, ERR_INSUFFICIENT_Y_AMOUNT); + (x_out, y_out) + } + + /// Swap X to Y + /// swap from X to Y + public fun swap_coins_for_coins( + coins_in: Coin, + ): Coin acquires LiquidityPool, AdminData, Events { + let amount_in = coin::value(&coins_in); + let swap_fee = borrow_global(RESOURCE_ACCOUNT_ADDRESS).swap_fee; + let (reserve_in, reserve_out) = get_reserves_size(); + let amount_out = AnimeSwapPoolV1Library::get_amount_out(amount_in, reserve_in, reserve_out, swap_fee); + let (zero, coins_out); + if (AnimeSwapPoolV1Library::compare()) { + (zero, coins_out) = swap(coins_in, 0, coin::zero(), amount_out); + } else { + (coins_out, zero) = swap(coin::zero(), amount_out, coins_in, 0); + }; + coin::destroy_zero(zero); + coins_out + } + + /** + * Low level functions, can be called by other contracts + */ + + /// Mint new LPCoin + public fun mint( + coin_x: Coin, + coin_y: Coin + ): Coin> acquires LiquidityPool, AdminData, Events { + assert!(AnimeSwapPoolV1Library::compare(), ERR_PAIR_ORDER_ERROR); + assert!(exists>(RESOURCE_ACCOUNT_ADDRESS), ERR_PAIR_NOT_EXIST); + assert_not_paused(); + assert_lp_unlocked(); + + let amount_x = coin::value(&coin_x); + let amount_y = coin::value(&coin_y); + // get reserve + let lp = borrow_global_mut>(RESOURCE_ACCOUNT_ADDRESS); + let (reserve_x, reserve_y) = (coin::value(&lp.coin_x_reserve), coin::value(&lp.coin_y_reserve)); + let admin_data = borrow_global(RESOURCE_ACCOUNT_ADDRESS); + // feeOn + let fee_on = mint_fee_interval(lp, admin_data); + coin::merge(&mut lp.coin_x_reserve, coin_x); + coin::merge(&mut lp.coin_y_reserve, coin_y); + let (balance_x, balance_y) = (coin::value(&lp.coin_x_reserve), coin::value(&lp.coin_y_reserve)); + + let total_supply = AnimeSwapPoolV1Library::get_lpcoin_total_supply>(); + let liquidity; + if (total_supply == 0) { + liquidity = AnimeSwapPoolV1Library::sqrt(amount_x, amount_y) - MINIMUM_LIQUIDITY; + mint_coin(&get_resource_account_signer(), MINIMUM_LIQUIDITY, &lp.lp_mint_cap); + } else { + // normal tx should never overflow + let amount_1 = ((amount_x as u128) * total_supply / (reserve_x as u128) as u64); + let amount_2 = ((amount_y as u128) * total_supply / (reserve_y as u128) as u64); + liquidity = AnimeSwapPoolV1Library::min(amount_1, amount_2); + }; + assert!(liquidity > 0, ERR_INSUFFICIENT_LIQUIDITY_MINT); + let coins = coin::mint>(liquidity, &lp.lp_mint_cap); + // update interval + update_internal(lp, balance_x, balance_y, reserve_x, reserve_y); + // feeOn + if (fee_on) lp.k_last = (balance_x as u128) * (balance_y as u128); + // event + let events = borrow_global_mut>(RESOURCE_ACCOUNT_ADDRESS); + event::emit_event(&mut events.mint_event, MintEvent { + amount_x, + amount_y, + liquidity, + }); + coins + } + + /// Burn LPCoin and get back coins + public fun burn( + liquidity: Coin> + ): (Coin, Coin) acquires LiquidityPool, AdminData, Events { + assert!(AnimeSwapPoolV1Library::compare(), ERR_PAIR_ORDER_ERROR); + assert_lp_unlocked(); + let liquidity_amount = coin::value(&liquidity); + // get lp + let lp = borrow_global_mut>(RESOURCE_ACCOUNT_ADDRESS); + let (reserve_x, reserve_y) = (coin::value(&lp.coin_x_reserve), coin::value(&lp.coin_y_reserve)); + let admin_data = borrow_global(RESOURCE_ACCOUNT_ADDRESS); + // feeOn + let fee_on = mint_fee_interval(lp, admin_data); + + let total_supply = AnimeSwapPoolV1Library::get_lpcoin_total_supply>(); + let amount_x = ((liquidity_amount as u128) * (reserve_x as u128) / total_supply as u64); + let amount_y = ((liquidity_amount as u128) * (reserve_y as u128) / total_supply as u64); + let x_coin_to_return = coin::extract(&mut lp.coin_x_reserve, amount_x); + let y_coin_to_return = coin::extract(&mut lp.coin_y_reserve, amount_y); + assert!(amount_x > 0 && amount_y > 0, ERR_INSUFFICIENT_LIQUIDITY_BURN); + let (balance_x, balance_y) = (coin::value(&lp.coin_x_reserve), coin::value(&lp.coin_y_reserve)); + coin::burn>(liquidity, &lp.lp_burn_cap); + + // update interval + update_internal(lp, balance_x, balance_y, reserve_x, reserve_y); + // feeOn + if (fee_on) lp.k_last = (balance_x as u128) * (balance_y as u128); + // event + let events = borrow_global_mut>(RESOURCE_ACCOUNT_ADDRESS); + event::emit_event(&mut events.burn_event, BurnEvent { + amount_x, + amount_y, + liquidity: liquidity_amount, + }); + (x_coin_to_return, y_coin_to_return) + } + + /// Swap coins + public fun swap( + coins_x_in: Coin, + amount_x_out: u64, + coins_y_in: Coin, + amount_y_out: u64, + ): (Coin, Coin) acquires LiquidityPool, AdminData, Events { + assert_not_paused(); + assert_lp_unlocked(); + let amount_x_in = coin::value(&coins_x_in); + let amount_y_in = coin::value(&coins_y_in); + assert!(amount_x_in > 0 || amount_y_in > 0, ERR_INSUFFICIENT_INPUT_AMOUNT); + assert!(amount_x_out > 0 || amount_y_out > 0, ERR_INSUFFICIENT_OUTPUT_AMOUNT); + let lp = borrow_global_mut>(RESOURCE_ACCOUNT_ADDRESS); + let (reserve_x, reserve_y) = (coin::value(&lp.coin_x_reserve), coin::value(&lp.coin_y_reserve)); + coin::merge(&mut lp.coin_x_reserve, coins_x_in); + coin::merge(&mut lp.coin_y_reserve, coins_y_in); + let coins_x_out = coin::extract(&mut lp.coin_x_reserve, amount_x_out); + let coins_y_out = coin::extract(&mut lp.coin_y_reserve, amount_y_out); + let (balance_x, balance_y) = (coin::value(&lp.coin_x_reserve), coin::value(&lp.coin_y_reserve)); + assert_k_increase(balance_x, balance_y, amount_x_in, amount_y_in, reserve_x, reserve_y); + // update internal + update_internal(lp, balance_x, balance_y, reserve_x, reserve_y); + // event + let events = borrow_global_mut>(RESOURCE_ACCOUNT_ADDRESS); + event::emit_event(&mut events.swap_event, SwapEvent { + amount_x_in, + amount_y_in, + amount_x_out, + amount_y_out, + }); + (coins_x_out, coins_y_out) + } + + /** + * Misc public functions for other contract + */ + + /// price oracle for other contract + public fun get_last_price_cumulative(): (u128, u128, u64) acquires LiquidityPool { + if (AnimeSwapPoolV1Library::compare()) { + let lp = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + (lp.last_price_x_cumulative, lp.last_price_y_cumulative, lp.last_block_timestamp) + } else { + let lp = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + (lp.last_price_y_cumulative, lp.last_price_x_cumulative, lp.last_block_timestamp) + } + } + + public fun check_pair_exist(): bool { + if (AnimeSwapPoolV1Library::compare()) { + exists>(RESOURCE_ACCOUNT_ADDRESS) + } else { + exists>(RESOURCE_ACCOUNT_ADDRESS) + } + } + + public fun get_admin_data(): (u64, u8, bool, bool) acquires AdminData { + let admin_data = borrow_global(RESOURCE_ACCOUNT_ADDRESS); + (admin_data.swap_fee, admin_data.dao_fee, admin_data.dao_fee_on, admin_data.is_pause) + } + + public fun get_pair_list(): vector acquires PairInfo { + let pair_info = borrow_global(RESOURCE_ACCOUNT_ADDRESS); + pair_info.pair_list + } + + /** + * Flash swap functions, be called by other contracts + */ + + /// Get flash swap coins. User can loan any coins, and repay in the same tx. + /// In most cases, user may loan one coin, and repay the same or the other coin. + /// require X < Y. + /// * `loan_coin_x` - expected amount of X coins to loan. + /// * `loan_coin_y` - expected amount of Y coins to loan. + /// Returns both loaned X and Y coins: `(Coin, Coin, Flashloan( + loan_coin_x: u64, + loan_coin_y: u64 + ): (Coin, Coin, FlashSwap) acquires LiquidityPool, AdminData { + // assert check + assert!(AnimeSwapPoolV1Library::compare(), ERR_PAIR_ORDER_ERROR); + assert!(loan_coin_x > 0 || loan_coin_y > 0, ERR_LOAN_ERROR); + assert_not_paused(); + assert_lp_unlocked(); + + let lp = borrow_global_mut>(RESOURCE_ACCOUNT_ADDRESS); + assert!(coin::value(&lp.coin_x_reserve) >= loan_coin_x && coin::value(&lp.coin_y_reserve) >= loan_coin_y, ERR_INSUFFICIENT_AMOUNT); + lp.locked = true; + + let loaned_coin_x = coin::extract(&mut lp.coin_x_reserve, loan_coin_x); + let loaned_coin_y = coin::extract(&mut lp.coin_y_reserve, loan_coin_y); + + // Return loaned amount. + (loaned_coin_x, loaned_coin_y, FlashSwap {loan_coin_x, loan_coin_y}) + } + + /// Repay flash swap coins. + /// User should repay amount, following the conditions: + /// `new_pool_1_value * new_pool_2_value >= old_pool_1_value * old_pool_2_value` + /// where `new_pool_x_value` is the `old_pool_x_value - amount_out + amount_in * (1 - swapFee)`, + /// and `pool_x_value` is the reserve amount for a given CoinType. + /// * `x_in` - X coins to pay. + /// * `y_in` - Y coins to pay. + /// * `flash_swap` - flash_swap return. + public fun pay_flash_swap( + x_in: Coin, + y_in: Coin, + flash_swap: FlashSwap + ) acquires LiquidityPool, AdminData, Events { + // assert check + assert!(AnimeSwapPoolV1Library::compare(), ERR_PAIR_ORDER_ERROR); + assert!(exists>(RESOURCE_ACCOUNT_ADDRESS), ERR_PAIR_NOT_EXIST); + assert_not_paused(); + + let FlashSwap { loan_coin_x, loan_coin_y } = flash_swap; + let amount_x_in = coin::value(&x_in); + let amount_y_in = coin::value(&y_in); + + assert!(amount_x_in > 0 || amount_y_in > 0, ERR_LOAN_ERROR); + + let lp = borrow_global_mut>(RESOURCE_ACCOUNT_ADDRESS); + let reserve_x = coin::value(&lp.coin_x_reserve); + let reserve_y = coin::value(&lp.coin_y_reserve); + + // reserve size before loan out + reserve_x = reserve_x + loan_coin_x; + reserve_y = reserve_y + loan_coin_y; + + coin::merge(&mut lp.coin_x_reserve, x_in); + coin::merge(&mut lp.coin_y_reserve, y_in); + + let balance_x = coin::value(&lp.coin_x_reserve); + let balance_y = coin::value(&lp.coin_y_reserve); + assert_k_increase(balance_x, balance_y, amount_x_in, amount_y_in, reserve_x, reserve_y); + // update internal + update_internal(lp, balance_x, balance_y, reserve_x, reserve_y); + + lp.locked = false; + // event + let events = borrow_global_mut>(RESOURCE_ACCOUNT_ADDRESS); + event::emit_event(&mut events.flash_swap_event, FlashSwapEvent { + loan_coin_x, + loan_coin_y, + repay_coin_x: amount_x_in, + repay_coin_y: amount_y_in, + }); + } + + #[test_only] + use aptos_framework::genesis; + #[test_only] + use aptos_framework::account::create_account_for_test; + #[test_only] + const TEST_ERROR:u64 = 10000; + #[test_only] + const ADD_LIQUIDITY_ERROR:u64 = 10003; + #[test_only] + const CONTRACTOR_BALANCE_ERROR:u64 = 10004; + #[test_only] + const USER_LP_BALANCE_ERROR:u64 = 10005; + #[test_only] + const INIT_FAUCET_COIN:u64 = 1000000000; + + #[test_only] + struct Aptos {} + #[test_only] + struct AptosB {} + #[test_only] + struct BTC {} + #[test_only] + struct USDT {} + #[test_only] + struct Caps has key { + mint: MintCapability, + freeze: FreezeCapability, + burn: BurnCapability, + } + + #[test_only] + fun init_module_test(resource_account: &signer) acquires AdminData, PairInfo { + move_to(resource_account, AdminData { + signer_cap: account::create_test_signer_cap(signer::address_of(resource_account)), + dao_fee_to: DEPLOYER_ADDRESS, + admin_address: DEPLOYER_ADDRESS, + dao_fee: 5, // 1/6 to dao fee + swap_fee: 30, // 0.3% + dao_fee_on: false, // default false + is_pause: false, // default false + }); + move_to(resource_account, PairInfo{ + pair_list: vector::empty(), + }); + // create default 3 pairs + create_pair(); + create_pair(); + create_pair(); + } + + #[test_only] + fun test_init(creator: &signer, resource_account: &signer, someone_else: &signer) acquires AdminData, PairInfo { + genesis::setup(); + create_account_for_test(signer::address_of(creator)); + create_account_for_test(signer::address_of(resource_account)); + create_account_for_test(signer::address_of(someone_else)); + init_module_test(resource_account); + + // init timestamp + timestamp::update_global_time_for_test(100); + + { + // init self-defined BTC + let (apt_b, apt_f, apt_m) = coin::initialize(creator, utf8(b"Bitcoin"), utf8(b"BTC"), 6, true); + coin::register(resource_account); + coin::register(someone_else); + let coins = coin::mint(INIT_FAUCET_COIN, &apt_m); + coin::deposit(signer::address_of(someone_else), coins); + move_to(resource_account, Caps { mint: apt_m, freeze: apt_f, burn: apt_b }); + }; + + { + // init self-defined USDT + let (apt_b, apt_f, apt_m) = coin::initialize(creator, utf8(b"Tether"), utf8(b"USDT"), 6, true); + coin::register(resource_account); + coin::register(someone_else); + let coins = coin::mint(INIT_FAUCET_COIN, &apt_m); + coin::deposit(signer::address_of(someone_else), coins); + move_to(resource_account, Caps { mint: apt_m, freeze: apt_f, burn: apt_b }); + }; + + { + // init self-defined Aptos + let (apt_b, apt_f, apt_m) = coin::initialize(creator, utf8(b"Aptos"), utf8(b"APT"), 6, true); + coin::register(resource_account); + coin::register(someone_else); + let coins = coin::mint(INIT_FAUCET_COIN, &apt_m); + coin::deposit(signer::address_of(someone_else), coins); + move_to(resource_account, Caps { mint: apt_m, freeze: apt_f, burn: apt_b }); + }; + + { + // init self-defined AptosB + let (apt_b, apt_f, apt_m) = coin::initialize(creator, utf8(b"AptosB"), utf8(b"APTB"), 6, true); + coin::register(resource_account); + coin::register(someone_else); + let coins = coin::mint(INIT_FAUCET_COIN, &apt_m); + coin::deposit(signer::address_of(someone_else), coins); + move_to(resource_account, Caps { mint: apt_m, freeze: apt_f, burn: apt_b }); + }; + + create_pair(); + create_pair(); + create_pair(); + } + + #[test_only] + fun test_init_another_one(resource_account: &signer, another_one: &signer) acquires Caps { + create_account_for_test(signer::address_of(another_one)); + { + coin::register(another_one); + let caps = borrow_global>(signer::address_of(resource_account)); + let coins = coin::mint(INIT_FAUCET_COIN, &caps.mint); + coin::deposit(signer::address_of(another_one), coins); + }; + { + coin::register(another_one); + let caps = borrow_global>(signer::address_of(resource_account)); + let coins = coin::mint(INIT_FAUCET_COIN, &caps.mint); + coin::deposit(signer::address_of(another_one), coins); + }; + } + + #[test(creator = @SwapDeployer, resource_account = @ResourceAccountDeployer, someone_else = @0x11)] + public entry fun test_add_remove_liquidity_basic_1_1(creator: &signer, resource_account: &signer, someone_else: &signer) + acquires LiquidityPool, AdminData, PairInfo, Events { + // init + test_init(creator, resource_account, someone_else); + + // should takes 10000/10000 coin and gives 9000 LPCoin (AnimeSwapPoolV1Library::sqrt(10000*10000)-1000) + add_liquidity_entry(someone_else, 10000, 10000, 1, 1); + { + let lp = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + assert!(coin::value(&lp.coin_x_reserve) == 10000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp.coin_y_reserve) == 10000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::balance>(signer::address_of(someone_else)) == 9000, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 10000, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 10000, USER_LP_BALANCE_ERROR); + }; + + // should takes 100/100 coin and gives 100 LPCoin + add_liquidity_entry(someone_else, 1000, 100, 1, 1); + { + let lp = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + assert!(coin::value(&lp.coin_x_reserve) == 10100, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp.coin_y_reserve) == 10100, CONTRACTOR_BALANCE_ERROR); + assert!(coin::balance>(signer::address_of(someone_else)) == 9100, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 10100, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 10100, USER_LP_BALANCE_ERROR); + }; + + // should takes 9000 LPCoin and gives 9000/9000 coin + remove_liquidity_entry(someone_else, 9000, 9000, 9000); + { + let lp = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + assert!(coin::value(&lp.coin_x_reserve) == 1100, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp.coin_y_reserve) == 1100, CONTRACTOR_BALANCE_ERROR); + assert!(coin::balance>(signer::address_of(someone_else)) == 100, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 1100, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 1100, USER_LP_BALANCE_ERROR); + }; + } + + #[test(creator = @SwapDeployer, resource_account = @ResourceAccountDeployer, someone_else = @0x11)] + public entry fun test_add_remove_liquidity_basic_1_100(creator: &signer, resource_account: &signer, someone_else: &signer) + acquires LiquidityPool, AdminData, PairInfo, Events { + // init + test_init(creator, resource_account, someone_else); + + // should takes 1000/100000 coin and gives 9000 LPCoin (AnimeSwapPoolV1Library::sqrt(1000*100000)-1000) + add_liquidity_entry(someone_else, 1000, 100000, 1, 1); + { + let lp = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + assert!(coin::value(&lp.coin_x_reserve) == 1000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp.coin_y_reserve) == 100000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::balance>(signer::address_of(someone_else)) == 9000, USER_LP_BALANCE_ERROR); + }; + + // should takes 10/1000 coin and gives 100 LPCoin + add_liquidity_entry(someone_else, 1000, 1000, 1, 1); + { + let lp = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + assert!(coin::value(&lp.coin_x_reserve) == 1010, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp.coin_y_reserve) == 101000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::balance>(signer::address_of(someone_else)) == 9100, USER_LP_BALANCE_ERROR); + }; + + // should takes 9000 LPCoin and gives 900/90000 coin + remove_liquidity_entry(someone_else, 9000, 900, 90000); + { + let lp = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + assert!(coin::value(&lp.coin_x_reserve) == 110, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp.coin_y_reserve) == 11000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::balance>(signer::address_of(someone_else)) == 100, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 110, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 11000, USER_LP_BALANCE_ERROR); + }; + } + + #[test(creator = @SwapDeployer, resource_account = @ResourceAccountDeployer, someone_else = @0x11)] + public entry fun test_add_remove_liquidity_basic_1_2(creator: &signer, resource_account: &signer, someone_else: &signer) + acquires LiquidityPool, AdminData, PairInfo, Events { + // init + test_init(creator, resource_account, someone_else); + + // should takes 1000/2000 coin and gives 414 LPCoin (AnimeSwapPoolV1Library::sqrt(1000*2000)-1000) + add_liquidity_entry(someone_else, 1000, 2000, 1, 1); + { + let lp = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + assert!(coin::value(&lp.coin_x_reserve) == 1000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp.coin_y_reserve) == 2000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::balance>(signer::address_of(someone_else)) == 414, USER_LP_BALANCE_ERROR); + }; + + // should takes 1000/2000 coin and gives 1414 LPCoin + add_liquidity_entry(someone_else, 2000, 2000, 1, 1); + { + let lp = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + assert!(coin::value(&lp.coin_x_reserve) == 2000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp.coin_y_reserve) == 4000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::balance>(signer::address_of(someone_else)) == 1828, USER_LP_BALANCE_ERROR); + }; + + // should takes 1828 LPCoin and gives 1828/2828*2000=1292|1828/2828*4000=2585 coin + remove_liquidity_entry(someone_else, 1828, 1, 1); + { + let lp = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + assert!(coin::value(&lp.coin_x_reserve) == 2000-1292, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp.coin_y_reserve) == 4000-2585, CONTRACTOR_BALANCE_ERROR); + assert!(coin::balance>(signer::address_of(someone_else)) == 0, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - (2000-1292), USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - (4000-2585), USER_LP_BALANCE_ERROR); + }; + } + + #[test(creator = @SwapDeployer, resource_account = @ResourceAccountDeployer, someone_else = @0x11)] + public entry fun test_swap_basic_1(creator: &signer, resource_account: &signer, someone_else: &signer) + acquires LiquidityPool, AdminData, PairInfo, Events { + // init + test_init(creator, resource_account, someone_else); + + // should takes 10000/10000 coin and gives 9000 LPCoin (AnimeSwapPoolV1Library::sqrt(10000*10000)-1000) + add_liquidity_entry(someone_else, 10000, 10000, 1, 1); + { + let lp = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + assert!(coin::value(&lp.coin_x_reserve) == 10000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp.coin_y_reserve) == 10000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::balance>(signer::address_of(someone_else)) == 9000, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 10000, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 10000, USER_LP_BALANCE_ERROR); + }; + + swap_exact_coins_for_coins_entry(someone_else, 1000, 1); + { + let lp = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + assert!(coin::value(&lp.coin_x_reserve) == 11000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp.coin_y_reserve) == 9094, CONTRACTOR_BALANCE_ERROR); + assert!(coin::balance>(signer::address_of(someone_else)) == 9000, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 10000 - 1000, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 10000 + 906, USER_LP_BALANCE_ERROR); + }; + + swap_exact_coins_for_coins_entry(someone_else, 1000, 1); + { + let lp = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + assert!(coin::value(&lp.coin_x_reserve) == 9914, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp.coin_y_reserve) == 10094, CONTRACTOR_BALANCE_ERROR); + assert!(coin::balance>(signer::address_of(someone_else)) == 9000, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 10000 - 1000 + 1086, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 10000 + 906 - 1000, USER_LP_BALANCE_ERROR); + }; + + // should takes 1000 LPCoin and gives 1000/10000*9914=991|1000/10000*10094=1009 coin + remove_liquidity_entry(someone_else, 1000, 1, 1); + { + let lp = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + assert!(coin::value(&lp.coin_x_reserve) == 9914 - 991, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp.coin_y_reserve) == 10094 - 1009, CONTRACTOR_BALANCE_ERROR); + assert!(coin::balance>(signer::address_of(someone_else)) == 8000, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 10000 - 1000 + 1086 + 991, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 10000 + 906 - 1000 + 1009, USER_LP_BALANCE_ERROR); + }; + } + + #[test(creator = @SwapDeployer, resource_account = @ResourceAccountDeployer, someone_else = @0x11)] + public entry fun test_swap_basic_2(creator: &signer, resource_account: &signer, someone_else: &signer) + acquires LiquidityPool, AdminData, PairInfo, Events { + // init + test_init(creator, resource_account, someone_else); + + // should takes 10000/10000 coin and gives 9000 LPCoin (AnimeSwapPoolV1Library::sqrt(10000*10000)-1000) + add_liquidity_entry(someone_else, 10000, 10000, 1, 1); + { + let lp = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + assert!(coin::value(&lp.coin_x_reserve) == 10000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp.coin_y_reserve) == 10000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::balance>(signer::address_of(someone_else)) == 9000, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 10000, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 10000, USER_LP_BALANCE_ERROR); + }; + + swap_coins_for_exact_coins_entry(someone_else, 1000, 100000); + { + let lp = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + assert!(coin::value(&lp.coin_x_reserve) == 11115, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp.coin_y_reserve) == 9000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::balance>(signer::address_of(someone_else)) == 9000, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 10000 - 1115, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 10000 + 1000, USER_LP_BALANCE_ERROR); + }; + + swap_coins_for_exact_coins_entry(someone_else, 1000, 100000); + { + let lp = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + assert!(coin::value(&lp.coin_x_reserve) == 10115, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp.coin_y_reserve) == 9893, CONTRACTOR_BALANCE_ERROR); + assert!(coin::balance>(signer::address_of(someone_else)) == 9000, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 10000 - 1115 + 1000, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 10000 + 1000 - 893, USER_LP_BALANCE_ERROR); + }; + } + + #[test(creator = @SwapDeployer, resource_account = @ResourceAccountDeployer, someone_else = @0x11)] + public entry fun test_swap_multiple_pair_1_1(creator: &signer, resource_account: &signer, someone_else: &signer) + acquires LiquidityPool, AdminData, PairInfo, Events { + // init + test_init(creator, resource_account, someone_else); + + // should takes 10000/10000 coin and gives 9000 LPCoin (AnimeSwapPoolV1Library::sqrt(10000*10000)-1000) + add_liquidity_entry(someone_else, 10000000, 10000000, 1, 1); + add_liquidity_entry(someone_else, 10000000, 10000000, 1, 1); + + swap_exact_coins_for_coins_2_pair_entry(someone_else, 10000, 1); + { + let lp = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + let lp_2 = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + assert!(coin::value(&lp.coin_x_reserve) == 10010000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp.coin_y_reserve) == 9990040, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp_2.coin_x_reserve) == 10009960, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp_2.coin_y_reserve) == 9990080, CONTRACTOR_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 10000000 - 10000, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 20000000, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 10000000 + 9920, USER_LP_BALANCE_ERROR); + }; + } + + #[test(creator = @SwapDeployer, resource_account = @ResourceAccountDeployer, someone_else = @0x11)] + public entry fun test_swap_multiple_pair_1_2(creator: &signer, resource_account: &signer, someone_else: &signer) + acquires LiquidityPool, AdminData, PairInfo, Events { + // init + test_init(creator, resource_account, someone_else); + + // should takes 10000/10000 coin and gives 9000 LPCoin (AnimeSwapPoolV1Library::sqrt(10000*10000)-1000) + add_liquidity_entry(someone_else, 10000000, 10000000, 1, 1); + add_liquidity_entry(someone_else, 10000000, 10000000, 1, 1); + add_liquidity_entry(someone_else, 10000000, 10000000, 1, 1); + + swap_exact_coins_for_coins_3_pair_entry(someone_else, 10000, 1); + { + let lp = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + let lp_2 = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + let lp_3 = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + assert!(coin::value(&lp.coin_x_reserve) == 10010000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp.coin_y_reserve) == 9990040, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp_2.coin_x_reserve) == 10009960, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp_2.coin_y_reserve) == 9990080, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp_3.coin_x_reserve) == 10009920, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp_3.coin_y_reserve) == 9990120, CONTRACTOR_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 10000000 - 10000, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 20000000, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 20000000, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 10000000 + 9880, USER_LP_BALANCE_ERROR); + }; + } + + #[test(creator = @SwapDeployer, resource_account = @ResourceAccountDeployer, someone_else = @0x11)] + public entry fun test_swap_multiple_pair_2_1(creator: &signer, resource_account: &signer, someone_else: &signer) + acquires LiquidityPool, AdminData, PairInfo, Events { + // init + test_init(creator, resource_account, someone_else); + // std::aptos_coin::mint(signer::address_of(someone_else), 10000000); + + // should takes 10000/10000 coin and gives 9000 LPCoin (AnimeSwapPoolV1Library::sqrt(10000*10000)-1000) + add_liquidity_entry(someone_else, 10000000, 10000000, 1, 1); + add_liquidity_entry(someone_else, 10000000, 10000000, 1, 1); + + swap_coins_for_exact_coins_2_pair_entry(someone_else, 10000, 1000000); + { + let lp = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + let lp_2 = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + assert!(coin::value(&lp.coin_x_reserve) == 10010082, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp.coin_y_reserve) == 9989959, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp_2.coin_x_reserve) == 10010041, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp_2.coin_y_reserve) == 9990000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 10000000 - 10082, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 20000000, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 10000000 + 10000, USER_LP_BALANCE_ERROR); + } + } + + #[test(creator = @SwapDeployer, resource_account = @ResourceAccountDeployer, someone_else = @0x11)] + public entry fun test_swap_multiple_pair_2_1_1(creator: &signer, resource_account: &signer, someone_else: &signer) + acquires LiquidityPool, AdminData, PairInfo, Events { + // init + test_init(creator, resource_account, someone_else); + + add_liquidity_entry(someone_else, 100000000, 1000000, 1, 1); + add_liquidity_entry(someone_else, 1000000, 1000000, 1, 1); + + swap_coins_for_exact_coins_2_pair_entry(someone_else, 10000, 100000000000000); + { + let lp = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + let lp_2 = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + assert!(coin::value(&lp.coin_x_reserve) == 101026651, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp.coin_y_reserve) == 989868, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp_2.coin_x_reserve) == 1010132, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp_2.coin_y_reserve) == 990000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 100000000 - 1026651, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 2000000, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 1000000 + 10000, USER_LP_BALANCE_ERROR); + } + } + + #[test(creator = @SwapDeployer, resource_account = @ResourceAccountDeployer, someone_else = @0x11)] + public entry fun test_swap_multiple_pair_2_2(creator: &signer, resource_account: &signer, someone_else: &signer) + acquires LiquidityPool, AdminData, PairInfo, Events { + // init + test_init(creator, resource_account, someone_else); + + // should takes 10000/10000 coin and gives 9000 LPCoin (AnimeSwapPoolV1Library::sqrt(10000*10000)-1000) + add_liquidity_entry(someone_else, 10000000, 10000000, 1, 1); + add_liquidity_entry(someone_else, 10000000, 10000000, 1, 1); + add_liquidity_entry(someone_else, 10000000, 10000000, 1, 1); + + swap_coins_for_exact_coins_3_pair_entry(someone_else, 10000, 1000000); + { + let lp = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + let lp_2 = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + let lp_3 = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + assert!(coin::value(&lp.coin_x_reserve) == 10010123, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp.coin_y_reserve) == 9989918, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp_2.coin_x_reserve) == 10010082, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp_2.coin_y_reserve) == 9989959, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp_3.coin_x_reserve) == 10010041, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp_3.coin_y_reserve) == 9990000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 10000000 - 10123, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 20000000, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 20000000, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 10000000 + 10000, USER_LP_BALANCE_ERROR); + }; + } + + #[test(creator = @SwapDeployer, resource_account = @ResourceAccountDeployer, someone_else = @0x11)] + public entry fun test_swap_multiple_pair_2_2_1(creator: &signer, resource_account: &signer, someone_else: &signer) + acquires LiquidityPool, AdminData, PairInfo, Events { + // init + test_init(creator, resource_account, someone_else); + + add_liquidity_entry(someone_else, 10000000, 1000000, 1, 1); + add_liquidity_entry(someone_else, 1000000, 100000, 1, 1); + add_liquidity_entry(someone_else, 100000, 100000, 1, 1); + + swap_coins_for_exact_coins_3_pair_entry(someone_else, 1000, 100000000000000); + { + let lp = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + let lp_2 = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + let lp_3 = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + assert!(coin::value(&lp.coin_x_reserve) == 10104130, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp.coin_y_reserve) == 989725, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp_2.coin_x_reserve) == 1010275, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp_2.coin_y_reserve) == 98986, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp_3.coin_x_reserve) == 101014, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp_3.coin_y_reserve) == 99000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 10000000 - 104130, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 2000000, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 200000, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 100000 + 1000, USER_LP_BALANCE_ERROR); + }; + } + + // test remove more than expected + #[test(creator = @SwapDeployer, resource_account = @ResourceAccountDeployer, someone_else = @0x11)] + #[expected_failure(abort_code = 65542, location = coin)] + public entry fun test_add_remove_liquidity_error_1(creator: &signer, resource_account: &signer, someone_else: &signer) + acquires LiquidityPool, AdminData, PairInfo, Events { + // init + test_init(creator, resource_account, someone_else); + + // should takes 10000/10000 coin and gives 9000 LPCoin (AnimeSwapPoolV1Library::sqrt(10000*10000)-1000) + add_liquidity_entry(someone_else, 10000, 10000, 1, 1); + + // only have 9000 LP, should fail + remove_liquidity_entry(someone_else, 9200, 9200, 9200); + } + + // test remove more than expected + #[test(creator = @SwapDeployer, resource_account = @ResourceAccountDeployer, someone_else = @0x11)] + #[expected_failure(abort_code = ERR_INSUFFICIENT_Y_AMOUNT)] + public entry fun test_add_remove_liquidity_error_2(creator: &signer, resource_account: &signer, someone_else: &signer) + acquires LiquidityPool, AdminData, PairInfo, Events { + // init + test_init(creator, resource_account, someone_else); + + // should takes 10000/10000 coin and gives 9000 LPCoin (AnimeSwapPoolV1Library::sqrt(10000*10000)-1000) + add_liquidity_entry(someone_else, 10000, 10000, 1, 1); + + // should takes 9000 LPCoin and gives 900/90000 coin, but expect more + remove_liquidity_entry(someone_else, 9000, 1000, 100000); + } + + #[test(creator = @SwapDeployer, resource_account = @ResourceAccountDeployer, someone_else = @0x11)] + public entry fun test_add_multiple_liquidity(creator: &signer, resource_account: &signer, someone_else: &signer) + acquires LiquidityPool, AdminData, PairInfo, Events { + // init + test_init(creator, resource_account, someone_else); + + // add 3 LPs + add_liquidity_entry(someone_else, 1000000, 10000, 1, 1); + add_liquidity_entry(someone_else, 10000, 10000, 1, 1); + add_liquidity_entry(someone_else, 10000, 1000000, 1, 1); + + { + let lp = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + let lp_2 = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + let lp_3 = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + assert!(coin::value(&lp.coin_x_reserve) == 1000000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp.coin_y_reserve) == 10000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp_2.coin_x_reserve) == 10000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp_2.coin_y_reserve) == 10000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp_3.coin_x_reserve) == 10000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp_3.coin_y_reserve) == 1000000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::balance>(signer::address_of(someone_else)) == 99000, USER_LP_BALANCE_ERROR); + assert!(coin::balance>(signer::address_of(someone_else)) == 9000, USER_LP_BALANCE_ERROR); + assert!(coin::balance>(signer::address_of(someone_else)) == 99000, USER_LP_BALANCE_ERROR); + }; + + let lp_1 = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + assert!(coin::value(&lp_1.coin_x_reserve) == 1000000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp_1.coin_y_reserve) == 10000, CONTRACTOR_BALANCE_ERROR); + let lp_2 = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + assert!(coin::value(&lp_2.coin_x_reserve) == 10000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp_2.coin_y_reserve) == 10000, CONTRACTOR_BALANCE_ERROR); + let lp_3 = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + assert!(coin::value(&lp_3.coin_x_reserve) == 10000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp_3.coin_y_reserve) == 1000000, CONTRACTOR_BALANCE_ERROR); + + // add 3 LPs + add_liquidity_entry(someone_else, 1000000, 10000, 1, 1); + add_liquidity_entry(someone_else, 10000, 10000, 1, 1); + add_liquidity_entry(someone_else, 10000, 1000000, 1, 1); + + { + let lp = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + let lp_2 = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + let lp_3 = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + assert!(coin::value(&lp.coin_x_reserve) == 2000000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp.coin_y_reserve) == 20000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp_2.coin_x_reserve) == 20000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp_2.coin_y_reserve) == 20000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp_3.coin_x_reserve) == 20000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp_3.coin_y_reserve) == 2000000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::balance>(signer::address_of(someone_else)) == 199000, USER_LP_BALANCE_ERROR); + assert!(coin::balance>(signer::address_of(someone_else)) == 19000, USER_LP_BALANCE_ERROR); + assert!(coin::balance>(signer::address_of(someone_else)) == 199000, USER_LP_BALANCE_ERROR); + }; + + let lp_1 = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + assert!(coin::value(&lp_1.coin_x_reserve) == 2000000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp_1.coin_y_reserve) == 20000, CONTRACTOR_BALANCE_ERROR); + let lp_2 = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + assert!(coin::value(&lp_2.coin_x_reserve) == 20000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp_2.coin_y_reserve) == 20000, CONTRACTOR_BALANCE_ERROR); + let lp_3 = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + assert!(coin::value(&lp_3.coin_x_reserve) == 20000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp_3.coin_y_reserve) == 2000000, CONTRACTOR_BALANCE_ERROR); + } + + #[test(creator = @SwapDeployer, resource_account = @ResourceAccountDeployer, someone_else = @0x11, dao_fee_to = @0x99)] + public entry fun test_dao_fee(creator: &signer, resource_account: &signer, someone_else: &signer, dao_fee_to: &signer) + acquires LiquidityPool, AdminData, PairInfo, Events { + // init + test_init(creator, resource_account, someone_else); + create_account_for_test(signer::address_of(dao_fee_to)); + set_dao_fee(creator, 1); + set_dao_fee_to(creator, signer::address_of(dao_fee_to)); + + // should takes 10000/10000 coin and gives 9000 LPCoin (AnimeSwapPoolV1Library::sqrt(10000*10000)-1000) + add_liquidity_entry(someone_else, 100000000, 100000000, 1, 1); + { + let lp = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + assert!(coin::value(&lp.coin_x_reserve) == 100000000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp.coin_y_reserve) == 100000000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::balance>(signer::address_of(someone_else)) == 100000000 - 1000, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 100000000, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 100000000, USER_LP_BALANCE_ERROR); + }; + + swap_exact_coins_for_coins_entry(someone_else, 10000000, 1); + { + let lp = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + assert!(coin::value(&lp.coin_x_reserve) == 110000000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp.coin_y_reserve) == 90933892, CONTRACTOR_BALANCE_ERROR); // 1e8-floor(1e8-1e8**2/(1e8+0.0997e8)) + assert!(coin::balance>(signer::address_of(someone_else)) == 100000000 - 1000, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 100000000 - 10000000, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 100000000 + 9066108, USER_LP_BALANCE_ERROR); + }; + + // admin_data should have some dao LPCoins + remove_liquidity_entry(someone_else, 1000000, 1, 1); + { + let lp = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + assert!(coin::value(&lp.coin_x_reserve) == 108900076, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp.coin_y_reserve) == 90024616, CONTRACTOR_BALANCE_ERROR); + assert!(coin::balance>(signer::address_of(someone_else)) == 98999000, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 108900076, USER_LP_BALANCE_ERROR); + assert!(coin::balance(signer::address_of(someone_else)) == INIT_FAUCET_COIN - 90024616, USER_LP_BALANCE_ERROR); + assert!(coin::balance>(RESOURCE_ACCOUNT_ADDRESS) == 1000 + 6819, USER_LP_BALANCE_ERROR); + }; + + // dao withdraw fee + withdraw_dao_fee(dao_fee_to); + { + assert!(coin::balance>(RESOURCE_ACCOUNT_ADDRESS) == 1000, USER_LP_BALANCE_ERROR); + assert!(coin::balance>(signer::address_of(dao_fee_to)) == 6819, USER_LP_BALANCE_ERROR); + }; + } + + // test resource account equal + #[test(deployer = @SwapDeployer)] + public entry fun test_resource_account(deployer: &signer) { + genesis::setup(); + create_account_for_test(signer::address_of(deployer)); + let addr = account::create_resource_address(&signer::address_of(deployer), x"30"); + aptos_std::debug::print
(&addr); + assert!(addr == @ResourceAccountDeployer, TEST_ERROR); + } + + // borrow on boin and repay the other coin, greater than swap fee + // borrow BTC and repay USDT + #[test(creator = @SwapDeployer, resource_account = @ResourceAccountDeployer, someone_else = @0x11, another_one = @0x12)] + public entry fun test_flash_swap_a(creator: &signer, resource_account: &signer, someone_else: &signer, another_one : &signer) + acquires LiquidityPool, AdminData, PairInfo, Caps, Events { + // init + test_init(creator, resource_account, someone_else); + test_init_another_one(resource_account, another_one); + + // if swap 1000 coin, should be 10000-1000/100000+11145 remain + add_liquidity_entry(someone_else, 10000, 100000, 1, 1); + let amount_out = 1000; + let amount_in = get_amounts_in_1_pair(amount_out); + assert!(amount_in == 11145, TEST_ERROR); + let (coin_out_1, coin_out_2, flash_swap) = flash_swap(amount_out, 0); + coin::deposit(signer::address_of(another_one), coin_out_1); + coin::deposit(signer::address_of(another_one), coin_out_2); + let repay_coin = coin::withdraw(another_one, amount_in); + pay_flash_swap(coin::zero(), repay_coin, flash_swap); + { + let lp = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + assert!(coin::value(&lp.coin_x_reserve) == 10000 - 1000, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp.coin_y_reserve) == 100000 + 11145, CONTRACTOR_BALANCE_ERROR); + }; + } + + // borrow on boin and repay the other coin, greater than swap fee + // borrow USDT and repay BTC + #[test(creator = @SwapDeployer, resource_account = @ResourceAccountDeployer, someone_else = @0x11, another_one = @0x12)] + public entry fun test_flash_swap_b(creator: &signer, resource_account: &signer, someone_else: &signer, another_one : &signer) + acquires LiquidityPool, AdminData, PairInfo, Caps, Events { + // init + test_init(creator, resource_account, someone_else); + test_init_another_one(resource_account, another_one); + + // if swap 1000 coin, should be 10000+102/100000-1000 remain + add_liquidity_entry(someone_else, 10000, 100000, 1, 1); + let amount_out = 1000; + let amount_in = get_amounts_in_1_pair(amount_out); + assert!(amount_in == 102, TEST_ERROR); + let (coin_out_1, coin_out_2, flash_swap) = flash_swap(0, amount_out); + coin::deposit(signer::address_of(another_one), coin_out_1); + coin::deposit(signer::address_of(another_one), coin_out_2); + let repay_coin = coin::withdraw(another_one, amount_in); + pay_flash_swap(repay_coin, coin::zero(), flash_swap); + { + let lp = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + assert!(coin::value(&lp.coin_x_reserve) == 10000 + 102, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp.coin_y_reserve) == 100000 - 1000, CONTRACTOR_BALANCE_ERROR); + }; + } + + // ERR_K_ERROR, not enough coin repay + // borrow on boin and repay the other coin but less equal than swap fee + #[test(creator = @SwapDeployer, resource_account = @ResourceAccountDeployer, someone_else = @0x11, another_one = @0x12)] + #[expected_failure(abort_code = ERR_K_ERROR)] + public entry fun test_flash_swap_error(creator: &signer, resource_account: &signer, someone_else: &signer, another_one : &signer) + acquires LiquidityPool, AdminData, PairInfo, Caps, Events { + // init + test_init(creator, resource_account, someone_else); + test_init_another_one(resource_account, another_one); + + // if swap 1000 coin, should be 9000/11115 remain + add_liquidity_entry(someone_else, 10000, 10000, 1, 1); + let (coin_out_1, coin_out_2, flash_swap) = flash_swap(1000, 0); + coin::deposit(signer::address_of(another_one), coin_out_1); + coin::deposit(signer::address_of(another_one), coin_out_2); + let repay_coin = coin::withdraw(another_one, 1114); + pay_flash_swap(coin::zero(), repay_coin, flash_swap); + } + + // borrow both boins and repay greater than swap fee + #[test(creator = @SwapDeployer, resource_account = @ResourceAccountDeployer, someone_else = @0x11, another_one = @0x12)] + public entry fun test_flash_swap_2(creator: &signer, resource_account: &signer, someone_else: &signer, another_one : &signer) + acquires LiquidityPool, AdminData, PairInfo, Caps, Events { + // init + test_init(creator, resource_account, someone_else); + test_init_another_one(resource_account, another_one); + + add_liquidity_entry(someone_else, 10000, 10000, 1, 1); + let (coin_out_1, coin_out_2, flash_swap) = flash_swap(1000, 1000); + coin::deposit(signer::address_of(another_one), coin_out_1); + coin::deposit(signer::address_of(another_one), coin_out_2); + let repay_coin_x = coin::withdraw(another_one, 1004); + let repay_coin_y = coin::withdraw(another_one, 1003); + pay_flash_swap(repay_coin_x, repay_coin_y, flash_swap); + { + let lp = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + assert!(coin::value(&lp.coin_x_reserve) == 10004, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp.coin_y_reserve) == 10003, CONTRACTOR_BALANCE_ERROR); + }; + } + + // ERR_K_ERROR, not enough coin repay + // borrow both boins and repay less equal than swap fee + #[test(creator = @SwapDeployer, resource_account = @ResourceAccountDeployer, someone_else = @0x11, another_one = @0x12)] + #[expected_failure(abort_code = ERR_K_ERROR)] + public entry fun test_flash_swap_error_2(creator: &signer, resource_account: &signer, someone_else: &signer, another_one : &signer) + acquires LiquidityPool, AdminData, PairInfo, Caps, Events { + // init + test_init(creator, resource_account, someone_else); + test_init_another_one(resource_account, another_one); + + add_liquidity_entry(someone_else, 10000, 10000, 1, 1); + let (coin_out_1, coin_out_2, flash_swap) = flash_swap(1000, 1000); + coin::deposit(signer::address_of(another_one), coin_out_1); + coin::deposit(signer::address_of(another_one), coin_out_2); + let repay_coin_x = coin::withdraw(another_one, 1003); + let repay_coin_y = coin::withdraw(another_one, 1003); + pay_flash_swap(repay_coin_x, repay_coin_y, flash_swap); + } + + // borrow one boin and repay the same coin, greater than swap fee + #[test(creator = @SwapDeployer, resource_account = @ResourceAccountDeployer, someone_else = @0x11, another_one = @0x12)] + public entry fun test_flash_swap_3(creator: &signer, resource_account: &signer, someone_else: &signer, another_one : &signer) + acquires LiquidityPool, AdminData, PairInfo, Caps, Events { + // init + test_init(creator, resource_account, someone_else); + test_init_another_one(resource_account, another_one); + + add_liquidity_entry(someone_else, 10000, 10000, 1, 1); + let (coin_out_1, coin_out_2, flash_swap) = flash_swap(1000, 0); + coin::deposit(signer::address_of(another_one), coin_out_1); + coin::deposit(signer::address_of(another_one), coin_out_2); + let repay_coin_x = coin::withdraw(another_one, 1004); + pay_flash_swap(repay_coin_x, coin::zero(), flash_swap); + { + let lp = borrow_global>(RESOURCE_ACCOUNT_ADDRESS); + assert!(coin::value(&lp.coin_x_reserve) == 10004, CONTRACTOR_BALANCE_ERROR); + assert!(coin::value(&lp.coin_y_reserve) == 10000, CONTRACTOR_BALANCE_ERROR); + }; + } + + // ERR_K_ERROR, not enough coin repay + // borrow one boin and repay the same coin, but less equal than swap fee + #[test(creator = @SwapDeployer, resource_account = @ResourceAccountDeployer, someone_else = @0x11, another_one = @0x12)] + #[expected_failure(abort_code = ERR_K_ERROR)] + public entry fun test_flash_swap_error_3(creator: &signer, resource_account: &signer, someone_else: &signer, another_one : &signer) + acquires LiquidityPool, AdminData, PairInfo, Caps, Events { + // init + test_init(creator, resource_account, someone_else); + test_init_another_one(resource_account, another_one); + + add_liquidity_entry(someone_else, 10000, 10000, 1, 1); + let (coin_out_1, coin_out_2, flash_swap) = flash_swap(1000, 0); + coin::deposit(signer::address_of(another_one), coin_out_1); + coin::deposit(signer::address_of(another_one), coin_out_2); + let repay_coin_x = coin::withdraw(another_one, 1003); + pay_flash_swap(repay_coin_x, coin::zero(), flash_swap); + } + + #[test(creator = @SwapDeployer, resource_account = @ResourceAccountDeployer, someone_else = @0x11, another_one = @0x12)] + public entry fun test_tmp(creator: &signer, resource_account: &signer, someone_else: &signer, another_one : &signer) + acquires LiquidityPool, AdminData, PairInfo, Caps, Events { + // init + test_init(creator, resource_account, someone_else); + test_init_another_one(resource_account, another_one); + + // if swap 1000 coin, should be 10000-1000/100000+11145 remain + add_liquidity_entry(someone_else, 10000, 100000, 1, 1); + let amount_out = 1000; + let amount_in = get_amounts_in_1_pair(amount_out); + assert!(amount_in == 11145, TEST_ERROR); + let coins_in = coin::withdraw(another_one, amount_in); + let coins_out = swap_coins_for_coins(coins_in); + assert!(coin::value(&coins_out) >= amount_out, TEST_ERROR); + coin::deposit(signer::address_of(another_one), coins_out) + } +} \ No newline at end of file diff --git a/networks/suzuka/suzuka-client/src/tests/hey-partners/Swap/sources/swap_library.move b/networks/suzuka/suzuka-client/src/tests/hey-partners/Swap/sources/swap_library.move new file mode 100644 index 000000000..a6e81efea --- /dev/null +++ b/networks/suzuka/suzuka-client/src/tests/hey-partners/Swap/sources/swap_library.move @@ -0,0 +1,221 @@ +module SwapDeployer::AnimeSwapPoolV1Library { + use std::signer; + use std::type_info; + use aptos_std::string; + use aptos_std::comparator::Self; + use aptos_framework::coin; + use std::option::{Self}; + + /// Maximum of u128 + const MAX_U128: u128 = 340282366920938463463374607431768211455; + + /// When not enough amount for pool + const ERR_INSUFFICIENT_AMOUNT: u64 = 201; + /// When not enough liquidity amount + const ERR_INSUFFICIENT_LIQUIDITY: u64 = 202; + /// When not enough input amount + const ERR_INSUFFICIENT_INPUT_AMOUNT: u64 = 203; + /// When not enough output amount + const ERR_INSUFFICIENT_OUTPUT_AMOUNT: u64 = 204; + /// When two coin type is the same + const ERR_COIN_TYPE_SAME_ERROR: u64 = 205; + + /// given some amount of an asset and pair reserves, returns an equivalent amount of the other asset + public fun quote( + amount_x: u64, + reserve_x: u64, + reserve_y: u64 + ) :u64 { + assert!(amount_x > 0, ERR_INSUFFICIENT_AMOUNT); + assert!(reserve_x > 0 && reserve_y > 0, ERR_INSUFFICIENT_LIQUIDITY); + let amount_y = ((amount_x as u128) * (reserve_y as u128) / (reserve_x as u128) as u64); + amount_y + } + + /// given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset + public fun get_amount_out( + amount_in: u64, + reserve_in: u64, + reserve_out: u64, + swap_fee: u64 + ): u64 { + assert!(amount_in > 0, ERR_INSUFFICIENT_INPUT_AMOUNT); + assert!(reserve_in > 0 && reserve_out > 0, ERR_INSUFFICIENT_LIQUIDITY); + let amount_in_with_fee = (amount_in as u128) * ((10000 - swap_fee) as u128); + let numerator = amount_in_with_fee * (reserve_out as u128); + let denominator = (reserve_in as u128) * 10000 + amount_in_with_fee; + let amount_out = numerator / denominator; + (amount_out as u64) + } + + /// given an output amount of an asset and pair reserves, returns a required input amount of the other asset + public fun get_amount_in( + amount_out: u64, + reserve_in: u64, + reserve_out: u64, + swap_fee: u64 + ): u64 { + assert!(amount_out > 0, ERR_INSUFFICIENT_OUTPUT_AMOUNT); + assert!(reserve_in > 0 && reserve_out > 0, ERR_INSUFFICIENT_LIQUIDITY); + let numerator = (reserve_in as u128) * (amount_out as u128) * 10000; + let denominator = ((reserve_out - amount_out) as u128) * ((10000 - swap_fee) as u128); + let amount_in = numerator / denominator + 1; + (amount_in as u64) + } + + // sqrt function + public fun sqrt( + x: u64, + y: u64 + ): u64 { + sqrt_128((x as u128) * (y as u128)) + } + + /// babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method) + public fun sqrt_128( + y: u128 + ): u64 { + if (y < 4) { + if (y == 0) { + 0 + } else { + 1 + } + } else { + let z = y; + let x = y / 2 + 1; + while (x < z) { + z = x; + x = (y / x + x) / 2; + }; + (z as u64) + } + } + + /// return Math.min + public fun min( + x:u64, + y:u64 + ): u64 { + if (x < y) return x else return y + } + + /// Add but allow overflow + public fun overflow_add(a: u128, b: u128): u128 { + let r = MAX_U128 - b; + if (r < a) { + return a - r - 1 + }; + r = MAX_U128 - a; + if (r < b) { + return b - r - 1 + }; + a + b + } + + // Check if mul maybe overflow + // The result maybe false positive + public fun is_overflow_mul(a: u128, b: u128): bool { + MAX_U128 / b <= a + } + + // compare type, when use, CoinType1 should < CoinType2 + public fun compare(): bool{ + let type_name_coin_1 = type_info::type_name(); + let type_name_coin_2 = type_info::type_name(); + assert!(type_name_coin_1 != type_name_coin_2, ERR_COIN_TYPE_SAME_ERROR); + + if (string::length(&type_name_coin_1) < string::length(&type_name_coin_2)) return true; + if (string::length(&type_name_coin_1) > string::length(&type_name_coin_2)) return false; + + let struct_cmp = comparator::compare(&type_name_coin_1, &type_name_coin_2); + comparator::is_smaller_than(&struct_cmp) + } + + // get coin::supply + public fun get_lpcoin_total_supply(): u128 { + option::extract(&mut coin::supply()) + } + + // register coin if not registered + public fun register_coin( + account: &signer + ) { + let account_addr = signer::address_of(account); + if (!coin::is_account_registered(account_addr)) { + coin::register(account); + }; + } + + #[test_only] + const TEST_ERROR:u64 = 10000; + #[test_only] + const SQRT_ERROR:u64 = 10001; + #[test_only] + const QUOTE_ERROR:u64 = 10002; + + #[test] + public entry fun test_overflow_add() { + let u128_max_add_1_u256 = overflow_add(MAX_U128, 1); + let u128_max_add_2_u256 = overflow_add(MAX_U128, 2); + assert!(u128_max_add_1_u256 == 0, TEST_ERROR); + assert!(u128_max_add_2_u256 == 1, TEST_ERROR); + } + + #[test] + public entry fun test_is_overflow_mul() { + let overflow_1 = is_overflow_mul(MAX_U128 / 2, 3); + let overflow_2 = is_overflow_mul(MAX_U128 / 3, 3); // false positive + let not_overflow_1 = is_overflow_mul(MAX_U128 / 2 - 1, 2); + let not_overflow_2 = is_overflow_mul(MAX_U128 / 3 - 1, 3); + assert!(overflow_1, TEST_ERROR); + assert!(overflow_2, TEST_ERROR); + assert!(!not_overflow_1, TEST_ERROR); + assert!(!not_overflow_2, TEST_ERROR); + } + + #[test] + public entry fun test_sqrt() { + let a = sqrt(1, 100); + assert!(a == 10, SQRT_ERROR); + let a = sqrt(1, 1000); + assert!(a == 31, SQRT_ERROR); + let a = sqrt(10003, 7); + assert!(a == 264, SQRT_ERROR); + let a = sqrt(999999999999999, 1); + assert!(a == 31622776, SQRT_ERROR); + } + + #[test] + public entry fun test_quote() { + let a = quote(123, 456, 789); + assert!(a == 212, QUOTE_ERROR); + } + + #[test] + public entry fun test_get_amount_out() { + let a = get_amount_out(123456789, 456789123, 789123456, 30); + assert!(a == 167502115, TEST_ERROR); + } + + #[test] + public entry fun test_get_amount_in() { + let a = get_amount_in(123456789, 456789123, 789123456, 30); + assert!(a == 84972572, TEST_ERROR); + } + + #[test_only] + struct TestCoinA {} + #[test_only] + struct TestCoinB {} + #[test_only] + struct TestCoinAA {} + + #[test] + public entry fun test_compare() { + let a = compare(); + assert!(a == true, TEST_ERROR); + let a = compare(); + assert!(a == true, TEST_ERROR); + } +} \ No newline at end of file diff --git a/networks/suzuka/suzuka-client/src/tests/hey-partners/TestCoin/Move.toml b/networks/suzuka/suzuka-client/src/tests/hey-partners/TestCoin/Move.toml new file mode 100644 index 000000000..0c7630455 --- /dev/null +++ b/networks/suzuka/suzuka-client/src/tests/hey-partners/TestCoin/Move.toml @@ -0,0 +1,9 @@ +[package] +name = "TestCoin" +version = "0.3.0" + +[dependencies] +AptosFramework = { git = "https://github.com/aptos-labs/aptos-core.git", subdir = "aptos-move/framework/aptos-framework/", rev = "bbce0f188d7bef08218f1fc1f46bbd3676b5c74b" } + +[addresses] +SwapDeployer = "_" diff --git a/networks/suzuka/suzuka-client/src/tests/hey-partners/TestCoin/sources/testCoins.move b/networks/suzuka/suzuka-client/src/tests/hey-partners/TestCoin/sources/testCoins.move new file mode 100644 index 000000000..1242a651f --- /dev/null +++ b/networks/suzuka/suzuka-client/src/tests/hey-partners/TestCoin/sources/testCoins.move @@ -0,0 +1,53 @@ + + +module SwapDeployer::TestCoinsV1 { + use std::signer; + use std::string::utf8; + + use aptos_framework::coin::{Self, MintCapability, FreezeCapability, BurnCapability}; + + /// Represents test USDT coin. + struct USDT {} + + /// Represents test BTC coin. + struct BTC {} + + /// Storing mint/burn capabilities for `USDT` and `BTC` coins under user account. + struct Caps has key { + mint: MintCapability, + freeze: FreezeCapability, + burn: BurnCapability, + } + + /// Initializes `BTC` and `USDT` coins. + public entry fun initialize(admin: &signer) { + let (btc_b, btc_f, btc_m) = + coin::initialize(admin, + utf8(b"Bitcoin"), utf8(b"BTC"), 8, true); + let (usdt_b, usdt_f, usdt_m) = + coin::initialize(admin, + utf8(b"Tether"), utf8(b"USDT"), 8, true); + move_to(admin, Caps { mint: btc_m, freeze: btc_f, burn: btc_b }); + move_to(admin, Caps { mint: usdt_m, freeze: usdt_f, burn: usdt_b }); + register_coins_all(admin); + } + + // only resource_account should call this + public entry fun register_coins_all(account: &signer) { + let account_addr = signer::address_of(account); + if (!coin::is_account_registered(account_addr)) { + coin::register(account); + }; + if (!coin::is_account_registered(account_addr)) { + coin::register(account); + }; + } + + // Mints new coin `CoinType` on account `acc_addr`. + public entry fun mint_coin(admin: &signer, acc_addr: address, amount: u64) acquires Caps { + let admin_addr = signer::address_of(admin); + let caps = borrow_global>(admin_addr); + let coins = coin::mint(amount, &caps.mint); + coin::deposit(acc_addr, coins); + } +} \ No newline at end of file diff --git a/networks/suzuka/suzuka-client/src/tests/hey-partners/test.sh b/networks/suzuka/suzuka-client/src/tests/hey-partners/test.sh new file mode 100644 index 000000000..61d45ec45 --- /dev/null +++ b/networks/suzuka/suzuka-client/src/tests/hey-partners/test.sh @@ -0,0 +1,194 @@ +#!/bin/sh + +FULLNODE="http://localhost:30731" +FAUCET="http://localhost:30732" +PATH_TO_REPO="." + +ls + +cd src/tests/hey-partners + +# Initializes an account if keys are not present +initialize_output=$(echo -ne '\n' | aptos init --network custom --rest-url $FULLNODE --faucet-url $FAUCET --assume-yes) + +CONFIG_FILE=".aptos/config.yaml" + +if [ ! -f "$CONFIG_FILE" ]; then + echo "Initialization failed. Config file not found." + exit 1 +fi + +aptos move compile + +PrivateKey=$(grep 'private_key:' "$CONFIG_FILE" | awk -F': ' '{print $2}' | tr -d '"') + +# Lookup the SwapDeployer address +lookup_address_output=$(aptos account lookup-address) +echo "Lookup Address Output: $lookup_address_output" +SwapDeployer=0x$(echo "$lookup_address_output" | grep -o '"Result": "[0-9a-fA-F]\{64\}"' | sed 's/"Result": "\(.*\)"/\1/') +if [ -z "$SwapDeployer" ]; then + echo "SwapDeployer extraction failed." + exit 1 +fi + +# Lookup the ResourceAccountDeployer address test IS expected to fail as long as we can retrieve the account address anyway + test_resource_account_output=$(aptos move test --package-dir "$PATH_TO_REPO/Swap/" \ +--filter test_resource_account --named-addresses SwapDeployer=$SwapDeployer,uq64x64=$SwapDeployer,u256=$SwapDeployer,ResourceAccountDeployer=$SwapDeployer) +echo "Test Resource Account Output: $test_resource_account_output" +ResourceAccountDeployer=$(echo "$test_resource_account_output" | grep -o '\[debug\] @[^\s]*' | sed 's/\[debug\] @\(.*\)/\1/') +if [ -z "$ResourceAccountDeployer" ]; then + echo "ResourceAccountDeployer extraction failed." + exit 1 +fi + +# Save variable to .env file for SDK tests +add_or_update_env() { + local key=$1 + local value=$2 + local file=".env" + if grep -q "^$key=" "$file"; then + # Update the existing key with the new value + if [[ "$OSTYPE" == "darwin"* ]]; then + # macOS + sed -i '' "s/^$key=.*/$key=$value/" "$file" + else + # Linux and other Unix-like systems + sed -i "s/^$key=.*/$key=$value/" "$file" + fi + else + # Add the key-value pair if it doesn't exist + echo "$key=$value" >> "$file" + fi +} + +add_or_update_env "SWAP_DEPLOYER" $SwapDeployer +add_or_update_env "RESOURCE_ACCOUNT_DEPLOYER" $ResourceAccountDeployer +add_or_update_env "PRIVATE_KEY" $PrivateKey +add_or_update_env "FULLNODE" $FULLNODE +add_or_update_env "FAUCET" $FAUCET + +# publish +echo "Publish uq64x64" +aptos move publish --package-dir $PATH_TO_REPO/uq64x64/ --assume-yes --named-addresses uq64x64=$SwapDeployer +echo "Publish u256" +aptos move publish --package-dir $PATH_TO_REPO/u256/ --assume-yes --named-addresses u256=$SwapDeployer +echo "Publish TestCoin" +aptos move publish --package-dir $PATH_TO_REPO/TestCoin/ --assume-yes --named-addresses SwapDeployer=$SwapDeployer +echo "Publish Faucet" +aptos move publish --package-dir $PATH_TO_REPO/Faucet/ --assume-yes --named-addresses SwapDeployer=$SwapDeployer +echo "Publish Resource Account" +aptos move publish --package-dir $PATH_TO_REPO/LPResourceAccount/ --assume-yes --named-addresses SwapDeployer=$SwapDeployer +# create resource account & publish LPCoin +# use this command to compile LPCoin +aptos move compile --package-dir $PATH_TO_REPO/LPCoin/ --save-metadata --named-addresses ResourceAccountDeployer=$ResourceAccountDeployer +# get the first arg +arg1=$(hexdump -ve '1/1 "%02x"' $PATH_TO_REPO/LPCoin/build/LPCoin/package-metadata.bcs) +# get the second arg +arg2=$(hexdump -ve '1/1 "%02x"' $PATH_TO_REPO/LPCoin/build/LPCoin/bytecode_modules/LPCoinV1.mv) +# This command is to publish LPCoin contract, using ResourceAccountDeployer address. Note: replace two args with the above two hex +echo "Initialize LPAccount" +aptos move run --function-id ${SwapDeployer}::LPResourceAccount::initialize_lp_account \ +--args hex:$arg1 hex:$arg2 --assume-yes + +echo "Publishing MovementSwap" +aptos move publish --package-dir $PATH_TO_REPO/Swap/ --assume-yes --named-addresses uq64x64=$SwapDeployer,u256=$SwapDeployer,SwapDeployer=$SwapDeployer,ResourceAccountDeployer=$ResourceAccountDeployer + +# admin steps +# TestCoinsV1 +echo "Initialize TestCoinsV1" +aptos move run --function-id ${SwapDeployer}::TestCoinsV1::initialize --assume-yes +echo "Mint USDT TestCoinsV1" +aptos move run --function-id ${SwapDeployer}::TestCoinsV1::mint_coin \ +--args address:${SwapDeployer} u64:20000000000000000 \ +--type-args ${SwapDeployer}::TestCoinsV1::USDT --assume-yes +echo "Mint BTC TestCoinsV1" +aptos move run --function-id ${SwapDeployer}::TestCoinsV1::mint_coin \ +--args address:${SwapDeployer} u64:2000000000000 \ +--type-args ${SwapDeployer}::TestCoinsV1::BTC --assume-yes + +# FaucetV1 +echo "Create USDT FaucetV1" +aptos move run --function-id ${SwapDeployer}::FaucetV1::create_faucet \ +--args u64:10000000000000000 u64:1000000000 u64:3600 \ +--type-args ${SwapDeployer}::TestCoinsV1::USDT --assume-yes +echo "Create BTC FaucetV1" +aptos move run --function-id ${SwapDeployer}::FaucetV1::create_faucet \ +--args u64:1000000000000 u64:10000000 u64:3600 \ +--type-args ${SwapDeployer}::TestCoinsV1::BTC --assume-yes + +# AnimeSwapPool +echo "add USDT:MOVE pair" +aptos move run --function-id ${SwapDeployer}::AnimeSwapPoolV1::add_liquidity_entry \ +--args u64:10000000000 u64:100000000 u64:1 u64:1 \ +--type-args ${SwapDeployer}::TestCoinsV1::USDT 0x1::aptos_coin::AptosCoin --assume-yes +echo "add BTC:MOVE pair" +aptos move run --function-id ${SwapDeployer}::AnimeSwapPoolV1::add_liquidity_entry \ +--args u64:10000000 u64:100000000 u64:1 u64:1 \ +--type-args ${SwapDeployer}::TestCoinsV1::BTC 0x1::aptos_coin::AptosCoin --assume-yes +echo "add BTC:USDT pair" +aptos move run --function-id ${SwapDeployer}::AnimeSwapPoolV1::add_liquidity_entry \ +--args u64:100000000 u64:100000000000 u64:1 u64:1 \ +--type-args ${SwapDeployer}::TestCoinsV1::BTC ${SwapDeployer}::TestCoinsV1::USDT --assume-yes + +echo "Finished Admin Functions" +# user +# fund +echo "Request USDT" +aptos move run --function-id ${SwapDeployer}::FaucetV1::request \ +--args address:${SwapDeployer} \ +--type-args ${SwapDeployer}::TestCoinsV1::USDT --assume-yes +echo "Request BTC" +aptos move run --function-id ${SwapDeployer}::FaucetV1::request \ +--args address:${SwapDeployer} \ +--type-args ${SwapDeployer}::TestCoinsV1::BTC --assume-yes +# swap (type args shows the swap direction, in this example, swap BTC to APT) +echo "Swap exact BTC for MOVE" +aptos move run --function-id ${SwapDeployer}::AnimeSwapPoolV1::swap_exact_coins_for_coins_entry \ +--args u64:100 u64:1 \ +--type-args ${SwapDeployer}::TestCoinsV1::BTC 0x1::aptos_coin::AptosCoin --assume-yes +# swap +echo "Swap BTC for exact MOVE" +aptos move run --function-id ${SwapDeployer}::AnimeSwapPoolV1::swap_coins_for_exact_coins_entry \ +--args u64:100 u64:1000000000 \ +--type-args ${SwapDeployer}::TestCoinsV1::BTC 0x1::aptos_coin::AptosCoin --assume-yes +# multiple pair swap (this example, swap 100 BTC->APT->USDT) +echo "Swap BTC for USDT" +aptos move run --function-id ${SwapDeployer}::AnimeSwapPoolV1::swap_exact_coins_for_coins_2_pair_entry \ +--args u64:100 u64:1 \ +--type-args ${SwapDeployer}::TestCoinsV1::BTC 0x1::aptos_coin::AptosCoin ${SwapDeployer}::TestCoinsV1::USDT --assume-yes +# add lp (if pair not exist, will auto create lp first) +echo "Add LP for BTC:MOVE" +aptos move run --function-id ${SwapDeployer}::AnimeSwapPoolV1::add_liquidity_entry \ +--args u64:1000 u64:10000 u64:1 u64:1 \ +--type-args ${SwapDeployer}::TestCoinsV1::BTC 0x1::aptos_coin::AptosCoin --assume-yes +echo "Remove LP from BTC:MOVE" +aptos move run --function-id ${SwapDeployer}::AnimeSwapPoolV1::remove_liquidity_entry \ +--args u64:1000 u64:1 u64:1 \ +--type-args ${SwapDeployer}::TestCoinsV1::BTC 0x1::aptos_coin::AptosCoin --assume-yes + +# Admin cmd example +echo "Set dao fee" +aptos move run --function-id ${SwapDeployer}::AnimeSwapPoolV1::set_dao_fee_to \ +--args address:${SwapDeployer} --assume-yes +echo "Set admin address" +aptos move run --function-id ${SwapDeployer}::AnimeSwapPoolV1::set_admin_address \ +--args address:${SwapDeployer} --assume-yes +echo "set dao fee" +aptos move run --function-id ${SwapDeployer}::AnimeSwapPoolV1::set_dao_fee \ +--args u64:5 +echo "set swap fee" +aptos move run --function-id ${SwapDeployer}::AnimeSwapPoolV1::set_swap_fee \ +--args u64:30 --assume-yes +echo "withdraw dao fee" +aptos move run --function-id ${SwapDeployer}::AnimeSwapPoolV1::withdraw_dao_fee \ +--type-args ${SwapDeployer}::TestCoinsV1::BTC ${SwapDeployer}::TestCoinsV1::USDT --assume-yes +echo "pause" +aptos move run --function-id ${SwapDeployer}::AnimeSwapPoolV1::pause --assume-yes +echo "unpause" +aptos move run --function-id ${SwapDeployer}::AnimeSwapPoolV1::unpause --assume-yes + +echo "Finished User Functions" + +# Run SDK tests +echo "Running Typescript SDK tests" +npx ts-node ./tests/typescript-sdk/main.test.ts --yes \ No newline at end of file diff --git a/networks/suzuka/suzuka-client/src/tests/hey-partners/tests/rust-sdk/.cargo/config.toml b/networks/suzuka/suzuka-client/src/tests/hey-partners/tests/rust-sdk/.cargo/config.toml new file mode 100644 index 000000000..16f1e73ac --- /dev/null +++ b/networks/suzuka/suzuka-client/src/tests/hey-partners/tests/rust-sdk/.cargo/config.toml @@ -0,0 +1,2 @@ +[build] +rustflags = ["--cfg", "tokio_unstable"] \ No newline at end of file diff --git a/networks/suzuka/suzuka-client/src/tests/hey-partners/tests/rust-sdk/Cargo.toml b/networks/suzuka/suzuka-client/src/tests/hey-partners/tests/rust-sdk/Cargo.toml new file mode 100644 index 000000000..45edcc0ff --- /dev/null +++ b/networks/suzuka/suzuka-client/src/tests/hey-partners/tests/rust-sdk/Cargo.toml @@ -0,0 +1,7 @@ +[dependencies] +aptos-sdk = { git = "https://github.com/aptos-labs/aptos-core", branch = "devnet" } +dotenv = "0.15.0" + +[patch.crates-io] +merlin = { git = "https://github.com/aptos-labs/merlin" } +x25519-dalek = { git = "https://github.com/aptos-labs/x25519-dalek", branch = "zeroize_v1" } \ No newline at end of file diff --git a/networks/suzuka/suzuka-client/src/tests/hey-partners/tests/rust-sdk/main.rs b/networks/suzuka/suzuka-client/src/tests/hey-partners/tests/rust-sdk/main.rs new file mode 100644 index 000000000..c6fe9e8db --- /dev/null +++ b/networks/suzuka/suzuka-client/src/tests/hey-partners/tests/rust-sdk/main.rs @@ -0,0 +1,133 @@ +use anyhow::Result; +use load_soak_testing::execute_test; +use load_soak_testing::init_test; +use load_soak_testing::ExecutionConfig; +use load_soak_testing::Scenario; +use dotenv::*; +use std::env; + +use anyhow::{Error, Context, Result}; +use aptos_sdk::{ + coin_client::CoinClient, + rest_client::{ + Client, FaucetClient, + aptos_api_types::{U64, ViewRequest, EntryFunctionId, VersionedEvent} + }, + types::{LocalAccount, transaction::authenticator::AuthenticationKey}, + transaction_builder::TransactionBuilder, + move_types::{ + ident_str, + language_storage::{ModuleId, TypeTag}, + }, + crypto::{ed25519::{ Ed25519PrivateKey, Ed25519PublicKey, Ed25519Signature, PublicKey, PrivateKey}, ValidCryptoMaterialStringExt}, + transaction_builder::TransactionFactory, + types::{ + account_address::AccountAddress, + transaction::{ + EntryFunction, Script, SignedTransaction, TransactionArgument, TransactionPayload, + } + } +}; + +use once_cell::sync::Lazy; +use std::str::FromStr; +use url::Url; +use tiny_keccak::{Hasher, Sha3}; +use std::collections::BTreeMap; +use serde::{Serialize, Deserialize}; + + +#[tokio::main] +async fn main() -> Result<()> { + let mut path = env::current_dir().unwrap(); + path.push("../.env"); + from_path(&path).ok(); + + let FULLNODE = env::var("FULLNODE").unwrap(); + let SWAP_DEPLOYER = env::var("SWAP_DEPLOYER").unwrap(); + let RESOURCE_ACCOUNT = env::var("RESOURCE_ACCOUNT_DEPLOYER").unwrap(); + let PRIVATE_KEY = env::var("PRIVATE_KEY").unwrap(); + + // :!:>section_1a + let aptos = Client::new(FULLNODE.clone()); + let faucet = FaucetClient::new(FULLNODE.clone(), FULLNODE.clone()); // <:!:section_1a + + // :!:>section_1b + let coin_client = CoinClient::new(&rest_client); // <:!:section_1b + + // Create two accounts locally, Alice and Bob. + let mut deployer = LocalAccount::from_hex(&PRIVATE_KEY).unwrap(); + let mut alice = LocalAccount::generate(&mut rand::rngs::OsRng); + let bob = LocalAccount::generate(&mut rand::rngs::OsRng); + let amount = 100000000; + + + faucet.fundAccount(&alice.accountAddress(), amount).await?; + faucet.fundAccount(&bob.accountAddress(), amount).await?; + + const fund = aptos.getAccountInfo({ account_address: alice.accountAddress() }).await?; + println!("fund :{:?}", fund.inner()); + const modules = aptos.getModules({ account_address: deployer.accountAddress() }).await?; + println!("modules :{:?}", modules.inner()); + const tokens = aptos.getAccountOwnedTokens({ account_address: alice.accountAddress() }).await?; + println!("tokens :{:?}", tokens.inner()); +} + + +#[derive(Serialize,Deserialize, Debug)] +struct DispatchEventData { + dest_domain: u64, + message: String, + message_id: String, + recipient: String, + sender: String +} + +#[derive(Serialize, Deserialize, Debug)] +struct ValidatorsAndThresholdMoveValue { + validators: serde_json::Value, + threshold: String, +} + +fn main() { + // Define the Test config. Use the default parameters. + let config = ExecutionConfig::default(); + + // Init the Test before execution + if let Err(err) = init_test(&config) { + println!("Test init fail ; {err}",); + } + + // Execute the test. + let result = execute_test(config, &create_demo_scenario); + tracing::info!("End Test with result {result:?}",); +} + +// Scenario constructor function use by the Test runtime to create new scenarios. +fn create_demo_scenario(id: usize) -> Box { + Box::new(ScenarioDemo { id }) +} + +pub struct ScenarioDemo { + id: usize, +} + +impl ScenarioDemo { + pub fn new(id: usize) -> Self { + ScenarioDemo { id } + } +} + +// Scenario trait implementation. +#[async_trait::async_trait] +impl Scenario for ScenarioDemo { + async fn run(self: Box) -> Result { + // Trace in the log file and stdout. + tracing::info!("Scenarios:{} start", self.id); + let _ = tokio::time::sleep(tokio::time::Duration::from_millis(500)).await; + // Trace in the json formated execution log file. + self.log_exec_info(&format!("Scenario:{} ended", self.id)); + Ok(self.id) + } +} + diff --git a/networks/suzuka/suzuka-client/src/tests/hey-partners/tests/typescript-sdk/.gitignore b/networks/suzuka/suzuka-client/src/tests/hey-partners/tests/typescript-sdk/.gitignore new file mode 100644 index 000000000..b512c09d4 --- /dev/null +++ b/networks/suzuka/suzuka-client/src/tests/hey-partners/tests/typescript-sdk/.gitignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/networks/suzuka/suzuka-client/src/tests/hey-partners/tests/typescript-sdk/main.test.ts b/networks/suzuka/suzuka-client/src/tests/hey-partners/tests/typescript-sdk/main.test.ts new file mode 100644 index 000000000..dabe21a0a --- /dev/null +++ b/networks/suzuka/suzuka-client/src/tests/hey-partners/tests/typescript-sdk/main.test.ts @@ -0,0 +1,102 @@ +import { Aptos, AptosConfig, Account, Network, MoveModuleBytecode, AccountAddress, Ed25519PrivateKey, APTOS_COIN, HexInput } from "@aptos-labs/ts-sdk" +import dotenv from "dotenv" +// import 'mocha' +// import {expect} from "chai" + +// Specify the path to the .env file in the parent directory +dotenv.config({ path: '.env' }); + +if (!process.env.FULLNODE || !process.env.FAUCET || !process.env.PRIVATE_KEY || !process.env.SWAP_DEPLOYER || !process.env.RESOURCE_ACCOUNT_DEPLOYER) process.exit(1); +const SwapDeployer = process.env.SWAP_DEPLOYER; +const ResourceAccount = process.env.RESOURCE_ACCOUNT_DEPLOYER; + + +const aptosConfig = new AptosConfig({ network: Network.DEVNET, fullnode: process.env.FULLNODE, faucet: process.env.FAUCET }); +const aptos = new Aptos(aptosConfig); + +const privateKey = new Ed25519PrivateKey(process.env.PRIVATE_KEY as string); +const deployer = Account.fromPrivateKey({ privateKey }); + +const alice = Account.generate(); +const bob = Account.generate(); + +const amount = 100000000; + +async function transact(signer: any, func: `${string}::${string}::${string}`, typeArgs: string[], args: any[]) { + const transaction = await aptos.transaction.build.simple({ + sender: signer.accountAddress, + data: { + function: func, + typeArguments: [...typeArgs], + functionArguments: [...args], + }, + }); + const committedTransaction = await aptos.signAndSubmitTransaction({ signer: signer, transaction }); + return committedTransaction +} + +async function main() { + + console.log("Requesting funds for Alice from Alice") + try { + // await aptos.faucet.fundAccount({ accountAddress: alice.accountAddress, amount: amount }); + await fetch(`${process.env.FAUCET}/mint`, { method: 'POST', body: JSON.stringify({ address: alice.accountAddress, amount: amount }) }) + console.log("Account funded successfully."); + } catch (error : any) { + console.log(error) + console.error("Error funding account:", error); + console.error("Error details:", error.message || error); + } + console.log("Requesting funds for Alice from Bob") + // await aptos.faucet.fundAccount({ accountAddress: bob.accountAddress, amount: amount }) + await fetch(`${process.env.FAUCET}/mint`, { method: 'POST', body: JSON.stringify({ address: bob.accountAddress, amount: amount }) }) + + // describe("sdk", async () => { + // test("transaction reads", async () => { + + console.log("Getting account info for Alice") + const fund = await aptos.getAccountInfo({ accountAddress: alice.accountAddress }); + console.log("Getting account modules for deployer") + const modules = await aptos.getAccountModules({ accountAddress: deployer.accountAddress }); + console.log("Getting account owned tokens for deployer") + const tokens = await aptos.getAccountOwnedTokens({ accountAddress: deployer.accountAddress }); + console.log("Getting account resource for deployer") + const testCoinsV1 = await aptos.getAccountResource({ + accountAddress: deployer.accountAddress, + resourceType: `0x1::coin::CoinStore<${deployer.accountAddress}::TestCoinsV1::USDT>`, + }) + + // expect(fund).to.be(String(amount)); + // expect(modules[0].abi?.name).to.be(`uq64x64`) + // expect(tokens[0].token_standard).to.be('AptosCoin') + // }) + + + // test("transaction writes", async () => { + console.log("Minting USDT for deployer") + const mint = await transact(deployer, `${SwapDeployer}::TestCoinV1::mint_coin`, [`${SwapDeployer}::TestCoinsV1::USDT`], [20000000000000000]); + console.log("Requesting USDT for Alice") + const usdt_request = await transact(alice, `${SwapDeployer}::FaucetV1::request`, [`${SwapDeployer}::TestCoinsV1::USDT`], [alice.accountAddress]) + console.log("Requesting USDT for Alice from Bob") + const nice_request = await transact(bob, `${SwapDeployer}::FaucetV1::request`, [`${SwapDeployer}::TestCoinsV1::USDT`], [alice.accountAddress]) + + console.log("Requesting BTC for Alice") + const btc_request = await transact(alice, `${SwapDeployer}::FaucetV1::request`, [`${SwapDeployer}::TestCoinsV1::BTC`], [alice.accountAddress]) + // swap exact BTC + console.log("Swapping BTC for exact MOVE") + const btc_swap = await transact(alice, `${SwapDeployer}::AnimeSwapPoolV1::swap_exact_coins_for_coins_entry`, [`${SwapDeployer}::TestCoinsV1::BTC 0x1::aptos_coin::AptosCoin`], ['u64:100 u64:1000000000']) + // swap BTC for exact USDT + console.log("Swapping exact BTC for MOVE") + const btc_swap_exact = await transact(alice, `${SwapDeployer}::AnimeSwapPoolV1::swap_exact_coins_for_coins_entry`, [`${SwapDeployer}::TestCoinsV1::BTC 0x1::aptos_coin::AptosCoin`, `0x1::aptos_coin::AptosCoin`, `${SwapDeployer}::TestCoinsV1::USDT`], ['u64:100 u64:1']) + + // expect(mint.type).to.be(String(1)) + // expect(usdt_request.type).to.be(String(1)) + // expect(nice_request.type).to.be(String(1)) + // expect(btc_request.type).to.be(String(1)) + // expect(btc_swap.type).to.be(String(1)) + // expect(btc_swap_exact.type).to.be(String(1)) + // }) + // }) + +} +main().catch((err) => { console.log(err) }) \ No newline at end of file diff --git a/networks/suzuka/suzuka-client/src/tests/hey-partners/tests/typescript-sdk/package.json b/networks/suzuka/suzuka-client/src/tests/hey-partners/tests/typescript-sdk/package.json new file mode 100644 index 000000000..c41cf6a6d --- /dev/null +++ b/networks/suzuka/suzuka-client/src/tests/hey-partners/tests/typescript-sdk/package.json @@ -0,0 +1,20 @@ +{ + "dependencies": { + "@aptos-labs/ts-sdk": "^1.17.0", + "@types/jest": "^29.5.12", + "@types/mocha": "^10.0.6", + "@typescript-eslint/parser": "^7.12.0", + "chai": "^5.1.1", + "dotenv": "^16.4.5", + "eslint-plugin-import": "^2.29.1", + "jest": "^29.7.0", + "sinon": "^18.0.0", + "typescript": "^5.4.5" + }, + "devDependencies": { + "@types/chai": "^4.3.16", + "@types/jest": "^29.5.12", + "@types/mocha": "^10.0.6", + "mocha": "^10.4.0" + } +} diff --git a/networks/suzuka/suzuka-client/src/tests/hey-partners/tests/typescript-sdk/pnpm-lock.yaml b/networks/suzuka/suzuka-client/src/tests/hey-partners/tests/typescript-sdk/pnpm-lock.yaml new file mode 100644 index 000000000..067c2ace2 --- /dev/null +++ b/networks/suzuka/suzuka-client/src/tests/hey-partners/tests/typescript-sdk/pnpm-lock.yaml @@ -0,0 +1,4769 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@aptos-labs/ts-sdk': + specifier: ^1.17.0 + version: 1.18.0 + '@types/jest': + specifier: ^29.5.12 + version: 29.5.12 + '@types/mocha': + specifier: ^10.0.6 + version: 10.0.6 + '@typescript-eslint/parser': + specifier: ^7.12.0 + version: 7.12.0(eslint@8.57.0)(typescript@5.4.5) + chai: + specifier: ^5.1.1 + version: 5.1.1 + dotenv: + specifier: ^16.4.5 + version: 16.4.5 + eslint-plugin-import: + specifier: ^2.29.1 + version: 2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0) + jest: + specifier: ^29.7.0 + version: 29.7.0(@types/node@20.14.1) + sinon: + specifier: ^18.0.0 + version: 18.0.0 + typescript: + specifier: ^5.4.5 + version: 5.4.5 + devDependencies: + '@types/chai': + specifier: ^4.3.16 + version: 4.3.16 + mocha: + specifier: ^10.4.0 + version: 10.4.0 + +packages: + + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + + '@aptos-labs/aptos-cli@0.1.8': + resolution: {integrity: sha512-xSWDchqoDR4aR74xNoJZgOzIFtn+EKFGGFLG0vOb+6Ce8Jgg1Ui0Pqhvwbx6Z36dDxfKv0F4M7bnurvWpwAjXA==} + hasBin: true + + '@aptos-labs/aptos-client@0.1.0': + resolution: {integrity: sha512-q3s6pPq8H2buGp+tPuIRInWsYOuhSEwuNJPwd2YnsiID3YSLihn2ug39ktDJAcSOprUcp7Nid8WK7hKqnUmSdA==} + engines: {node: '>=15.10.0'} + + '@aptos-labs/ts-sdk@1.18.0': + resolution: {integrity: sha512-8nDYOH++PNV3ylj9VIBEgFQGl0bJ3AH1S3Sefsxd8vcJepBZBQN0dFt/tdewrFfLFLOCUa/+TjS8JoS/rd96nA==} + engines: {node: '>=11.0.0'} + + '@babel/code-frame@7.24.6': + resolution: {integrity: sha512-ZJhac6FkEd1yhG2AHOmfcXG4ceoLltoCVJjN5XsWN9BifBQr+cHJbWi0h68HZuSORq+3WtJ2z0hwF2NG1b5kcA==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.24.6': + resolution: {integrity: sha512-aC2DGhBq5eEdyXWqrDInSqQjO0k8xtPRf5YylULqx8MCd6jBtzqfta/3ETMRpuKIc5hyswfO80ObyA1MvkCcUQ==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.24.6': + resolution: {integrity: sha512-qAHSfAdVyFmIvl0VHELib8xar7ONuSHrE2hLnsaWkYNTI68dmi1x8GYDhJjMI/e7XWal9QBlZkwbOnkcw7Z8gQ==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.24.6': + resolution: {integrity: sha512-S7m4eNa6YAPJRHmKsLHIDJhNAGNKoWNiWefz1MBbpnt8g9lvMDl1hir4P9bo/57bQEmuwEhnRU/AMWsD0G/Fbg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.24.6': + resolution: {integrity: sha512-VZQ57UsDGlX/5fFA7GkVPplZhHsVc+vuErWgdOiysI9Ksnw0Pbbd6pnPiR/mmJyKHgyIW0c7KT32gmhiF+cirg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-environment-visitor@7.24.6': + resolution: {integrity: sha512-Y50Cg3k0LKLMjxdPjIl40SdJgMB85iXn27Vk/qbHZCFx/o5XO3PSnpi675h1KEmmDb6OFArfd5SCQEQ5Q4H88g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-function-name@7.24.6': + resolution: {integrity: sha512-xpeLqeeRkbxhnYimfr2PC+iA0Q7ljX/d1eZ9/inYbmfG2jpl8Lu3DyXvpOAnrS5kxkfOWJjioIMQsaMBXFI05w==} + engines: {node: '>=6.9.0'} + + '@babel/helper-hoist-variables@7.24.6': + resolution: {integrity: sha512-SF/EMrC3OD7dSta1bLJIlrsVxwtd0UpjRJqLno6125epQMJ/kyFmpTT4pbvPbdQHzCHg+biQ7Syo8lnDtbR+uA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.24.6': + resolution: {integrity: sha512-a26dmxFJBF62rRO9mmpgrfTLsAuyHk4e1hKTUkD/fcMfynt8gvEKwQPQDVxWhca8dHoDck+55DFt42zV0QMw5g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.24.6': + resolution: {integrity: sha512-Y/YMPm83mV2HJTbX1Qh2sjgjqcacvOlhbzdCCsSlblOKjSYmQqEbO6rUniWQyRo9ncyfjT8hnUjlG06RXDEmcA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-plugin-utils@7.24.6': + resolution: {integrity: sha512-MZG/JcWfxybKwsA9N9PmtF2lOSFSEMVCpIRrbxccZFLJPrJciJdG/UhSh5W96GEteJI2ARqm5UAHxISwRDLSNg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-simple-access@7.24.6': + resolution: {integrity: sha512-nZzcMMD4ZhmB35MOOzQuiGO5RzL6tJbsT37Zx8M5L/i9KSrukGXWTjLe1knIbb/RmxoJE9GON9soq0c0VEMM5g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-split-export-declaration@7.24.6': + resolution: {integrity: sha512-CvLSkwXGWnYlF9+J3iZUvwgAxKiYzK3BWuo+mLzD/MDGOZDj7Gq8+hqaOkMxmJwmlv0iu86uH5fdADd9Hxkymw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.24.6': + resolution: {integrity: sha512-WdJjwMEkmBicq5T9fm/cHND3+UlFa2Yj8ALLgmoSQAJZysYbBjw+azChSGPN4DSPLXOcooGRvDwZWMcF/mLO2Q==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.24.6': + resolution: {integrity: sha512-4yA7s865JHaqUdRbnaxarZREuPTHrjpDT+pXoAZ1yhyo6uFnIEpS8VMu16siFOHDpZNKYv5BObhsB//ycbICyw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.24.6': + resolution: {integrity: sha512-Jktc8KkF3zIkePb48QO+IapbXlSapOW9S+ogZZkcO6bABgYAxtZcjZ/O005111YLf+j4M84uEgwYoidDkXbCkQ==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.24.6': + resolution: {integrity: sha512-V2PI+NqnyFu1i0GyTd/O/cTpxzQCYioSkUIRmgo7gFEHKKCg5w46+r/A6WeUR1+P3TeQ49dspGPNd/E3n9AnnA==} + engines: {node: '>=6.9.0'} + + '@babel/highlight@7.24.6': + resolution: {integrity: sha512-2YnuOp4HAk2BsBrJJvYCbItHx0zWscI1C3zgWkz+wDyD9I7GIVrfnLyrR4Y1VR+7p+chAEcrgRQYZAGIKMV7vQ==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.24.6': + resolution: {integrity: sha512-eNZXdfU35nJC2h24RznROuOpO94h6x8sg9ju0tT9biNtLZ2vuP8SduLqqV+/8+cebSLV9SJEAN5Z3zQbJG/M+Q==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-syntax-async-generators@7.8.4': + resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-bigint@7.8.3': + resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-class-properties@7.12.13': + resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-meta@7.10.4': + resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-json-strings@7.8.3': + resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-jsx@7.24.6': + resolution: {integrity: sha512-lWfvAIFNWMlCsU0DRUun2GpFwZdGTukLaHJqRh1JRb80NdAP5Sb1HDHB5X9P9OtgZHQl089UzQkpYlBq2VTPRw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-logical-assignment-operators@7.10.4': + resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3': + resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-numeric-separator@7.10.4': + resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-object-rest-spread@7.8.3': + resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-optional-catch-binding@7.8.3': + resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-optional-chaining@7.8.3': + resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-top-level-await@7.14.5': + resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-typescript@7.24.6': + resolution: {integrity: sha512-TzCtxGgVTEJWWwcYwQhCIQ6WaKlo80/B+Onsk4RRCcYqpYGFcG9etPW94VToGte5AAcxRrhjPUFvUS3Y2qKi4A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/template@7.24.6': + resolution: {integrity: sha512-3vgazJlLwNXi9jhrR1ef8qiB65L1RK90+lEQwv4OxveHnqC3BfmnHdgySwRLzf6akhlOYenT+b7AfWq+a//AHw==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.24.6': + resolution: {integrity: sha512-OsNjaJwT9Zn8ozxcfoBc+RaHdj3gFmCmYoQLUII1o6ZrUwku0BMg80FoOTPx+Gi6XhcQxAYE4xyjPTo4SxEQqw==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.24.6': + resolution: {integrity: sha512-WaMsgi6Q8zMgMth93GvWPXkhAIEobfsIkLTacoVZoK1J0CevIPGYY2Vo5YvJGqyHqXM6P4ppOYGsIRU8MM9pFQ==} + engines: {node: '>=6.9.0'} + + '@bcoe/v8-coverage@0.2.3': + resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + + '@eslint-community/eslint-utils@4.4.0': + resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.10.1': + resolution: {integrity: sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/eslintrc@2.1.4': + resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@eslint/js@8.57.0': + resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@humanwhocodes/config-array@0.11.14': + resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} + engines: {node: '>=10.10.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/object-schema@2.0.3': + resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} + + '@istanbuljs/load-nyc-config@1.1.0': + resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} + engines: {node: '>=8'} + + '@istanbuljs/schema@0.1.3': + resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} + engines: {node: '>=8'} + + '@jest/console@29.7.0': + resolution: {integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/core@29.7.0': + resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + '@jest/environment@29.7.0': + resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/expect-utils@29.7.0': + resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/expect@29.7.0': + resolution: {integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/fake-timers@29.7.0': + resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/globals@29.7.0': + resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/reporters@29.7.0': + resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + '@jest/schemas@29.6.3': + resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/source-map@29.6.3': + resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/test-result@29.7.0': + resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/test-sequencer@29.7.0': + resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/transform@29.7.0': + resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/types@29.6.3': + resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jridgewell/gen-mapping@0.3.5': + resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} + engines: {node: '>=6.0.0'} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/set-array@1.2.1': + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.4.15': + resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + + '@jridgewell/trace-mapping@0.3.25': + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + + '@noble/curves@1.4.0': + resolution: {integrity: sha512-p+4cb332SFCrReJkCYe8Xzm0OWi4Jji5jVdIZRL/PmacmDkFNw6MrrV+gGpiPxLHbV+zKFRywUWbaseT+tZRXg==} + + '@noble/hashes@1.4.0': + resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} + engines: {node: '>= 16'} + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@scure/base@1.1.6': + resolution: {integrity: sha512-ok9AWwhcgYuGG3Zfhyqg+zwl+Wn5uE+dwC0NV/2qQkx4dABbb/bx96vWu8NSj+BNjjSjno+JRYRjle1jV08k3g==} + + '@scure/bip32@1.4.0': + resolution: {integrity: sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==} + + '@scure/bip39@1.3.0': + resolution: {integrity: sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==} + + '@sinclair/typebox@0.27.8': + resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} + + '@sindresorhus/is@4.6.0': + resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} + engines: {node: '>=10'} + + '@sinonjs/commons@2.0.0': + resolution: {integrity: sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==} + + '@sinonjs/commons@3.0.1': + resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} + + '@sinonjs/fake-timers@10.3.0': + resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} + + '@sinonjs/fake-timers@11.2.2': + resolution: {integrity: sha512-G2piCSxQ7oWOxwGSAyFHfPIsyeJGXYtc6mFbnFA+kRXkiEnTl8c/8jul2S329iFBnDI9HGoeWWAZvuvOkZccgw==} + + '@sinonjs/samsam@8.0.0': + resolution: {integrity: sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==} + + '@sinonjs/text-encoding@0.7.2': + resolution: {integrity: sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==} + + '@szmarczak/http-timer@4.0.6': + resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} + engines: {node: '>=10'} + + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + + '@types/babel__generator@7.6.8': + resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + + '@types/babel__traverse@7.20.6': + resolution: {integrity: sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==} + + '@types/cacheable-request@6.0.3': + resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==} + + '@types/chai@4.3.16': + resolution: {integrity: sha512-PatH4iOdyh3MyWtmHVFXLWCCIhUbopaltqddG9BzB+gMIzee2MJrvd+jouii9Z3wzQJruGWAm7WOMjgfG8hQlQ==} + + '@types/graceful-fs@4.1.9': + resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} + + '@types/http-cache-semantics@4.0.4': + resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==} + + '@types/istanbul-lib-coverage@2.0.6': + resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} + + '@types/istanbul-lib-report@3.0.3': + resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} + + '@types/istanbul-reports@3.0.4': + resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + + '@types/jest@29.5.12': + resolution: {integrity: sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==} + + '@types/json5@0.0.29': + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + + '@types/keyv@3.1.4': + resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} + + '@types/mocha@10.0.6': + resolution: {integrity: sha512-dJvrYWxP/UcXm36Qn36fxhUKu8A/xMRXVT2cliFF1Z7UA9liG5Psj3ezNSZw+5puH2czDXRLcXQxf8JbJt0ejg==} + + '@types/node@20.14.1': + resolution: {integrity: sha512-T2MzSGEu+ysB/FkWfqmhV3PLyQlowdptmmgD20C6QxsS8Fmv5SjpZ1ayXaEC0S21/h5UJ9iA6W/5vSNU5l00OA==} + + '@types/responselike@1.0.3': + resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} + + '@types/stack-utils@2.0.3': + resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + + '@types/yargs-parser@21.0.3': + resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} + + '@types/yargs@17.0.32': + resolution: {integrity: sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==} + + '@typescript-eslint/parser@7.12.0': + resolution: {integrity: sha512-dm/J2UDY3oV3TKius2OUZIFHsomQmpHtsV0FTh1WO8EKgHLQ1QCADUqscPgTpU+ih1e21FQSRjXckHn3txn6kQ==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + eslint: ^8.56.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/scope-manager@7.12.0': + resolution: {integrity: sha512-itF1pTnN6F3unPak+kutH9raIkL3lhH1YRPGgt7QQOh43DQKVJXmWkpb+vpc/TiDHs6RSd9CTbDsc/Y+Ygq7kg==} + engines: {node: ^18.18.0 || >=20.0.0} + + '@typescript-eslint/types@7.12.0': + resolution: {integrity: sha512-o+0Te6eWp2ppKY3mLCU+YA9pVJxhUJE15FV7kxuD9jgwIAa+w/ycGJBMrYDTpVGUM/tgpa9SeMOugSabWFq7bg==} + engines: {node: ^18.18.0 || >=20.0.0} + + '@typescript-eslint/typescript-estree@7.12.0': + resolution: {integrity: sha512-5bwqLsWBULv1h6pn7cMW5dXX/Y2amRqLaKqsASVwbBHMZSnHqE/HN4vT4fE0aFsiwxYvr98kqOWh1a8ZKXalCQ==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/visitor-keys@7.12.0': + resolution: {integrity: sha512-uZk7DevrQLL3vSnfFl5bj4sL75qC9D6EdjemIdbtkuUmIheWpuiiylSY01JxJE7+zGrOWDZrp1WxOuDntvKrHQ==} + engines: {node: ^18.18.0 || >=20.0.0} + + '@ungap/structured-clone@1.2.0': + resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.11.3: + resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + + ansi-colors@4.1.1: + resolution: {integrity: sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==} + engines: {node: '>=6'} + + ansi-escapes@4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + array-buffer-byte-length@1.0.1: + resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==} + engines: {node: '>= 0.4'} + + array-includes@3.1.8: + resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==} + engines: {node: '>= 0.4'} + + array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + + array.prototype.findlastindex@1.2.5: + resolution: {integrity: sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==} + engines: {node: '>= 0.4'} + + array.prototype.flat@1.3.2: + resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} + engines: {node: '>= 0.4'} + + array.prototype.flatmap@1.3.2: + resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} + engines: {node: '>= 0.4'} + + arraybuffer.prototype.slice@1.0.3: + resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==} + engines: {node: '>= 0.4'} + + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + + axios@1.6.2: + resolution: {integrity: sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==} + + babel-jest@29.7.0: + resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@babel/core': ^7.8.0 + + babel-plugin-istanbul@6.1.1: + resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} + engines: {node: '>=8'} + + babel-plugin-jest-hoist@29.6.3: + resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + babel-preset-current-node-syntax@1.0.1: + resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==} + peerDependencies: + '@babel/core': ^7.0.0 + + babel-preset-jest@29.6.3: + resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@babel/core': ^7.0.0 + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + + brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + + brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + browser-stdout@1.3.1: + resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==} + + browserslist@4.23.0: + resolution: {integrity: sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + bser@2.1.1: + resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + cacheable-lookup@5.0.4: + resolution: {integrity: sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==} + engines: {node: '>=10.6.0'} + + cacheable-request@7.0.4: + resolution: {integrity: sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==} + engines: {node: '>=8'} + + call-bind@1.0.7: + resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} + engines: {node: '>= 0.4'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + camelcase@5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + + camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + + caniuse-lite@1.0.30001627: + resolution: {integrity: sha512-4zgNiB8nTyV/tHhwZrFs88ryjls/lHiqFhrxCW4qSTeuRByBVnPYpDInchOIySWknznucaf31Z4KYqjfbrecVw==} + + chai@5.1.1: + resolution: {integrity: sha512-pT1ZgP8rPNqUgieVaEY+ryQr6Q4HXNg8Ei9UnLUrjN4IA7dvQC5JB+/kxVcPNDHyBcc/26CXPkbNzq3qwrOEKA==} + engines: {node: '>=12'} + + chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + char-regex@1.0.2: + resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} + engines: {node: '>=10'} + + check-error@2.1.1: + resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} + engines: {node: '>= 16'} + + chokidar@3.5.3: + resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} + engines: {node: '>= 8.10.0'} + + ci-info@3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} + + cjs-module-lexer@1.3.1: + resolution: {integrity: sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q==} + + cliui@7.0.4: + resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} + + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + + clone-response@1.0.3: + resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==} + + co@4.6.0: + resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} + engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + + collect-v8-coverage@1.0.2: + resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} + + color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + create-jest@29.7.0: + resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + + cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + + data-view-buffer@1.0.1: + resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==} + engines: {node: '>= 0.4'} + + data-view-byte-length@1.0.1: + resolution: {integrity: sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==} + engines: {node: '>= 0.4'} + + data-view-byte-offset@1.0.0: + resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==} + engines: {node: '>= 0.4'} + + debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.3.4: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.3.5: + resolution: {integrity: sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decamelize@4.0.0: + resolution: {integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==} + engines: {node: '>=10'} + + decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + + dedent@1.5.3: + resolution: {integrity: sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==} + peerDependencies: + babel-plugin-macros: ^3.1.0 + peerDependenciesMeta: + babel-plugin-macros: + optional: true + + deep-eql@5.0.2: + resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} + engines: {node: '>=6'} + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + + defer-to-connect@2.0.1: + resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} + engines: {node: '>=10'} + + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + detect-newline@3.1.0: + resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} + engines: {node: '>=8'} + + diff-sequences@29.6.3: + resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + diff@5.0.0: + resolution: {integrity: sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==} + engines: {node: '>=0.3.1'} + + diff@5.2.0: + resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==} + engines: {node: '>=0.3.1'} + + dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + + doctrine@2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + engines: {node: '>=0.10.0'} + + doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + + dotenv@16.4.5: + resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==} + engines: {node: '>=12'} + + electron-to-chromium@1.4.789: + resolution: {integrity: sha512-0VbyiaXoT++Fi2vHGo2ThOeS6X3vgRCWrjPeO2FeIAWL6ItiSJ9BqlH8LfCXe3X1IdcG+S0iLoNaxQWhfZoGzQ==} + + emittery@0.13.1: + resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} + engines: {node: '>=12'} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + end-of-stream@1.4.4: + resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + + error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + + es-abstract@1.23.3: + resolution: {integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==} + engines: {node: '>= 0.4'} + + es-define-property@1.0.0: + resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.0.0: + resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.0.3: + resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==} + engines: {node: '>= 0.4'} + + es-shim-unscopables@1.0.2: + resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} + + es-to-primitive@1.2.1: + resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} + engines: {node: '>= 0.4'} + + escalade@3.1.2: + resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} + engines: {node: '>=6'} + + escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + + escape-string-regexp@2.0.0: + resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} + engines: {node: '>=8'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + eslint-import-resolver-node@0.3.9: + resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} + + eslint-module-utils@2.8.1: + resolution: {integrity: sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + + eslint-plugin-import@2.29.1: + resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + + eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint@8.57.0: + resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + hasBin: true + + espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + + esquery@1.5.0: + resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + eventemitter3@5.0.1: + resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + + execa@5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + + exit@0.1.2: + resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} + engines: {node: '>= 0.8.0'} + + expect@29.7.0: + resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fastq@1.17.1: + resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + + fb-watchman@2.0.2: + resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + + file-entry-cache@6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} + engines: {node: ^10.12.0 || >=12.0.0} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat-cache@3.2.0: + resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} + engines: {node: ^10.12.0 || >=12.0.0} + + flat@5.0.2: + resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} + hasBin: true + + flatted@3.3.1: + resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} + + follow-redirects@1.15.6: + resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + for-each@0.3.3: + resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + + form-data@4.0.0: + resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + engines: {node: '>= 6'} + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + function.prototype.name@1.1.6: + resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} + engines: {node: '>= 0.4'} + + functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-func-name@2.0.2: + resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} + + get-intrinsic@1.2.4: + resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} + engines: {node: '>= 0.4'} + + get-package-type@0.1.0: + resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} + engines: {node: '>=8.0.0'} + + get-stream@5.2.0: + resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} + engines: {node: '>=8'} + + get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + + get-symbol-description@1.0.2: + resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} + engines: {node: '>= 0.4'} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported + + glob@8.1.0: + resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} + engines: {node: '>=12'} + deprecated: Glob versions prior to v9 are no longer supported + + globals@11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + + globals@13.24.0: + resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} + engines: {node: '>=8'} + + globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} + + globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + + gopd@1.0.1: + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + + got@11.8.6: + resolution: {integrity: sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==} + engines: {node: '>=10.19.0'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + + has-bigints@1.0.2: + resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} + + has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-proto@1.0.3: + resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} + engines: {node: '>= 0.4'} + + has-symbols@1.0.3: + resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + he@1.2.0: + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} + hasBin: true + + html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + + http-cache-semantics@4.1.1: + resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} + + http2-wrapper@1.0.3: + resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==} + engines: {node: '>=10.19.0'} + + human-signals@2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + + ignore@5.3.1: + resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} + engines: {node: '>= 4'} + + import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + + import-local@3.1.0: + resolution: {integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==} + engines: {node: '>=8'} + hasBin: true + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + inflight@1.0.6: + resolution: {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. + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + internal-slot@1.0.7: + resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} + engines: {node: '>= 0.4'} + + is-array-buffer@3.0.4: + resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} + engines: {node: '>= 0.4'} + + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + + is-bigint@1.0.4: + resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} + + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + + is-boolean-object@1.1.2: + resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} + engines: {node: '>= 0.4'} + + is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + + is-core-module@2.13.1: + resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} + + is-data-view@1.0.1: + resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==} + engines: {node: '>= 0.4'} + + is-date-object@1.0.5: + resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} + engines: {node: '>= 0.4'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-generator-fn@2.1.0: + resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} + engines: {node: '>=6'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} + engines: {node: '>= 0.4'} + + is-number-object@1.0.7: + resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} + engines: {node: '>= 0.4'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + + is-plain-obj@2.1.0: + resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} + engines: {node: '>=8'} + + is-regex@1.1.4: + resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} + engines: {node: '>= 0.4'} + + is-shared-array-buffer@1.0.3: + resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==} + engines: {node: '>= 0.4'} + + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + + is-string@1.0.7: + resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} + engines: {node: '>= 0.4'} + + is-symbol@1.0.4: + resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} + engines: {node: '>= 0.4'} + + is-typed-array@1.1.13: + resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} + engines: {node: '>= 0.4'} + + is-unicode-supported@0.1.0: + resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} + engines: {node: '>=10'} + + is-weakref@1.0.2: + resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} + + isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + istanbul-lib-coverage@3.2.2: + resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} + engines: {node: '>=8'} + + istanbul-lib-instrument@5.2.1: + resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} + engines: {node: '>=8'} + + istanbul-lib-instrument@6.0.2: + resolution: {integrity: sha512-1WUsZ9R1lA0HtBSohTkm39WTPlNKSJ5iFk7UwqXkBLoHQT+hfqPsfsTDVuZdKGaBwn7din9bS7SsnoAr943hvw==} + engines: {node: '>=10'} + + istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} + engines: {node: '>=10'} + + istanbul-lib-source-maps@4.0.1: + resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} + engines: {node: '>=10'} + + istanbul-reports@3.1.7: + resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==} + engines: {node: '>=8'} + + jest-changed-files@29.7.0: + resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-circus@29.7.0: + resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-cli@29.7.0: + resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + jest-config@29.7.0: + resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@types/node': '*' + ts-node: '>=9.0.0' + peerDependenciesMeta: + '@types/node': + optional: true + ts-node: + optional: true + + jest-diff@29.7.0: + resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-docblock@29.7.0: + resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-each@29.7.0: + resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-environment-node@29.7.0: + resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-get-type@29.6.3: + resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-haste-map@29.7.0: + resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-leak-detector@29.7.0: + resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-matcher-utils@29.7.0: + resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-message-util@29.7.0: + resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-mock@29.7.0: + resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-pnp-resolver@1.2.3: + resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} + engines: {node: '>=6'} + peerDependencies: + jest-resolve: '*' + peerDependenciesMeta: + jest-resolve: + optional: true + + jest-regex-util@29.6.3: + resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-resolve-dependencies@29.7.0: + resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-resolve@29.7.0: + resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-runner@29.7.0: + resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-runtime@29.7.0: + resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-snapshot@29.7.0: + resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-util@29.7.0: + resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-validate@29.7.0: + resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-watcher@29.7.0: + resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-worker@29.7.0: + resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest@29.7.0: + resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + js-base64@3.7.7: + resolution: {integrity: sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@3.14.1: + resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} + hasBin: true + + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + + jsesc@2.5.2: + resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} + engines: {node: '>=4'} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + json5@1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + hasBin: true + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + just-extend@6.2.0: + resolution: {integrity: sha512-cYofQu2Xpom82S6qD778jBDpwvvy39s1l/hrYij2u9AMdQcGRpaBu6kY4mVhuno5kJVi1DAz4aiphA2WI1/OAw==} + + jwt-decode@4.0.0: + resolution: {integrity: sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==} + engines: {node: '>=18'} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + kleur@3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + + leven@3.1.0: + resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} + engines: {node: '>=6'} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash.get@4.4.2: + resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + log-symbols@4.1.0: + resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} + engines: {node: '>=10'} + + loupe@3.1.1: + resolution: {integrity: sha512-edNu/8D5MKVfGVFRhFf8aAxiTM6Wumfz5XsaatSxlD3w4R1d/WEKUTydCdPGbl9K7QG/Ca3GnDV2sIKIpXRQcw==} + + lowercase-keys@2.0.0: + resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==} + engines: {node: '>=8'} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + + makeerror@1.0.12: + resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromatch@4.0.7: + resolution: {integrity: sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==} + engines: {node: '>=8.6'} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + + mimic-response@1.0.1: + resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==} + engines: {node: '>=4'} + + mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@5.0.1: + resolution: {integrity: sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==} + engines: {node: '>=10'} + + minimatch@9.0.4: + resolution: {integrity: sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==} + engines: {node: '>=16 || 14 >=14.17'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + mocha@10.4.0: + resolution: {integrity: sha512-eqhGB8JKapEYcC4ytX/xrzKforgEc3j1pGlAXVy3eRwrtAy5/nIfT1SvgGzfN0XZZxeLq0aQWkOUAmqIJiv+bA==} + engines: {node: '>= 14.0.0'} + hasBin: true + + ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + nise@6.0.0: + resolution: {integrity: sha512-K8ePqo9BFvN31HXwEtTNGzgrPpmvgciDsFz8aztFjt4LqKO/JeFD8tBOeuDiCMXrIl/m1YvfH8auSpxfaD09wg==} + + node-int64@0.4.0: + resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} + + node-releases@2.0.14: + resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + normalize-url@6.1.0: + resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} + engines: {node: '>=10'} + + npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + + object-inspect@1.13.1: + resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} + + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + object.assign@4.1.5: + resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==} + engines: {node: '>= 0.4'} + + object.fromentries@2.0.8: + resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} + engines: {node: '>= 0.4'} + + object.groupby@1.0.3: + resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} + engines: {node: '>= 0.4'} + + object.values@1.2.0: + resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==} + engines: {node: '>= 0.4'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + p-cancelable@2.1.1: + resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==} + engines: {node: '>=8'} + + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + path-to-regexp@6.2.2: + resolution: {integrity: sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==} + + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + pathval@2.0.0: + resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==} + engines: {node: '>= 14.16'} + + picocolors@1.0.1: + resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + pirates@4.0.6: + resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} + engines: {node: '>= 6'} + + pkg-dir@4.2.0: + resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} + engines: {node: '>=8'} + + poseidon-lite@0.2.0: + resolution: {integrity: sha512-vivDZnGmz8W4G/GzVA72PXkfYStjilu83rjjUfpL4PueKcC8nfX6hCPh2XhoC5FBgC6y0TA3YuUeUo5YCcNoig==} + + possible-typed-array-names@1.0.0: + resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} + engines: {node: '>= 0.4'} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + pretty-format@29.7.0: + resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + prompts@2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + + pump@3.0.0: + resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + pure-rand@6.1.0: + resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + quick-lru@5.1.1: + resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} + engines: {node: '>=10'} + + randombytes@2.1.0: + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + + react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + + regexp.prototype.flags@1.5.2: + resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==} + engines: {node: '>= 0.4'} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + resolve-alpn@1.2.1: + resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} + + resolve-cwd@3.0.0: + resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} + engines: {node: '>=8'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + + resolve.exports@2.0.2: + resolution: {integrity: sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==} + engines: {node: '>=10'} + + resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + + responselike@2.0.1: + resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==} + + reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + safe-array-concat@1.1.2: + resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} + engines: {node: '>=0.4'} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safe-regex-test@1.0.3: + resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} + engines: {node: '>= 0.4'} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.6.2: + resolution: {integrity: sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==} + engines: {node: '>=10'} + hasBin: true + + serialize-javascript@6.0.0: + resolution: {integrity: sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==} + + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + side-channel@1.0.6: + resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} + engines: {node: '>= 0.4'} + + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + + sinon@18.0.0: + resolution: {integrity: sha512-+dXDXzD1sBO6HlmZDd7mXZCR/y5ECiEiGCBSGuFD/kZ0bDTofPYc6JaeGmPSF+1j1MejGUWkORbYOLDyvqCWpA==} + + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + source-map-support@0.5.13: + resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + + stack-utils@2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} + engines: {node: '>=10'} + + string-length@4.0.2: + resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} + engines: {node: '>=10'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string.prototype.trim@1.2.9: + resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==} + engines: {node: '>= 0.4'} + + string.prototype.trimend@1.0.8: + resolution: {integrity: sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==} + + string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + + strip-bom@4.0.0: + resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} + engines: {node: '>=8'} + + strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + test-exclude@6.0.0: + resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} + engines: {node: '>=8'} + + text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + + tmpl@1.0.5: + resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} + + to-fast-properties@2.0.0: + resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} + engines: {node: '>=4'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + ts-api-utils@1.3.0: + resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} + engines: {node: '>=16'} + peerDependencies: + typescript: '>=4.2.0' + + tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + type-detect@4.0.8: + resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} + engines: {node: '>=4'} + + type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + + type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + + typed-array-buffer@1.0.2: + resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} + engines: {node: '>= 0.4'} + + typed-array-byte-length@1.0.1: + resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==} + engines: {node: '>= 0.4'} + + typed-array-byte-offset@1.0.2: + resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==} + engines: {node: '>= 0.4'} + + typed-array-length@1.0.6: + resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==} + engines: {node: '>= 0.4'} + + typescript@5.4.5: + resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} + engines: {node: '>=14.17'} + hasBin: true + + unbox-primitive@1.0.2: + resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} + + undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + + update-browserslist-db@1.0.16: + resolution: {integrity: sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + v8-to-istanbul@9.2.0: + resolution: {integrity: sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==} + engines: {node: '>=10.12.0'} + + walker@1.0.8: + resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} + + which-boxed-primitive@1.0.2: + resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} + + which-typed-array@1.1.15: + resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} + engines: {node: '>= 0.4'} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + workerpool@6.2.1: + resolution: {integrity: sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + write-file-atomic@4.0.2: + resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yargs-parser@20.2.4: + resolution: {integrity: sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==} + engines: {node: '>=10'} + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs-unparser@2.0.0: + resolution: {integrity: sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==} + engines: {node: '>=10'} + + yargs@16.2.0: + resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} + engines: {node: '>=10'} + + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + +snapshots: + + '@ampproject/remapping@2.3.0': + dependencies: + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + + '@aptos-labs/aptos-cli@0.1.8': {} + + '@aptos-labs/aptos-client@0.1.0': + dependencies: + axios: 1.6.2 + got: 11.8.6 + transitivePeerDependencies: + - debug + + '@aptos-labs/ts-sdk@1.18.0': + dependencies: + '@aptos-labs/aptos-cli': 0.1.8 + '@aptos-labs/aptos-client': 0.1.0 + '@noble/curves': 1.4.0 + '@noble/hashes': 1.4.0 + '@scure/bip32': 1.4.0 + '@scure/bip39': 1.3.0 + eventemitter3: 5.0.1 + form-data: 4.0.0 + js-base64: 3.7.7 + jwt-decode: 4.0.0 + poseidon-lite: 0.2.0 + transitivePeerDependencies: + - debug + + '@babel/code-frame@7.24.6': + dependencies: + '@babel/highlight': 7.24.6 + picocolors: 1.0.1 + + '@babel/compat-data@7.24.6': {} + + '@babel/core@7.24.6': + dependencies: + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.24.6 + '@babel/generator': 7.24.6 + '@babel/helper-compilation-targets': 7.24.6 + '@babel/helper-module-transforms': 7.24.6(@babel/core@7.24.6) + '@babel/helpers': 7.24.6 + '@babel/parser': 7.24.6 + '@babel/template': 7.24.6 + '@babel/traverse': 7.24.6 + '@babel/types': 7.24.6 + convert-source-map: 2.0.0 + debug: 4.3.5 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.24.6': + dependencies: + '@babel/types': 7.24.6 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + jsesc: 2.5.2 + + '@babel/helper-compilation-targets@7.24.6': + dependencies: + '@babel/compat-data': 7.24.6 + '@babel/helper-validator-option': 7.24.6 + browserslist: 4.23.0 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-environment-visitor@7.24.6': {} + + '@babel/helper-function-name@7.24.6': + dependencies: + '@babel/template': 7.24.6 + '@babel/types': 7.24.6 + + '@babel/helper-hoist-variables@7.24.6': + dependencies: + '@babel/types': 7.24.6 + + '@babel/helper-module-imports@7.24.6': + dependencies: + '@babel/types': 7.24.6 + + '@babel/helper-module-transforms@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-environment-visitor': 7.24.6 + '@babel/helper-module-imports': 7.24.6 + '@babel/helper-simple-access': 7.24.6 + '@babel/helper-split-export-declaration': 7.24.6 + '@babel/helper-validator-identifier': 7.24.6 + + '@babel/helper-plugin-utils@7.24.6': {} + + '@babel/helper-simple-access@7.24.6': + dependencies: + '@babel/types': 7.24.6 + + '@babel/helper-split-export-declaration@7.24.6': + dependencies: + '@babel/types': 7.24.6 + + '@babel/helper-string-parser@7.24.6': {} + + '@babel/helper-validator-identifier@7.24.6': {} + + '@babel/helper-validator-option@7.24.6': {} + + '@babel/helpers@7.24.6': + dependencies: + '@babel/template': 7.24.6 + '@babel/types': 7.24.6 + + '@babel/highlight@7.24.6': + dependencies: + '@babel/helper-validator-identifier': 7.24.6 + chalk: 2.4.2 + js-tokens: 4.0.0 + picocolors: 1.0.1 + + '@babel/parser@7.24.6': + dependencies: + '@babel/types': 7.24.6 + + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + + '@babel/plugin-syntax-jsx@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + + '@babel/plugin-syntax-typescript@7.24.6(@babel/core@7.24.6)': + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.6 + + '@babel/template@7.24.6': + dependencies: + '@babel/code-frame': 7.24.6 + '@babel/parser': 7.24.6 + '@babel/types': 7.24.6 + + '@babel/traverse@7.24.6': + dependencies: + '@babel/code-frame': 7.24.6 + '@babel/generator': 7.24.6 + '@babel/helper-environment-visitor': 7.24.6 + '@babel/helper-function-name': 7.24.6 + '@babel/helper-hoist-variables': 7.24.6 + '@babel/helper-split-export-declaration': 7.24.6 + '@babel/parser': 7.24.6 + '@babel/types': 7.24.6 + debug: 4.3.5 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.24.6': + dependencies: + '@babel/helper-string-parser': 7.24.6 + '@babel/helper-validator-identifier': 7.24.6 + to-fast-properties: 2.0.0 + + '@bcoe/v8-coverage@0.2.3': {} + + '@eslint-community/eslint-utils@4.4.0(eslint@8.57.0)': + dependencies: + eslint: 8.57.0 + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.10.1': {} + + '@eslint/eslintrc@2.1.4': + dependencies: + ajv: 6.12.6 + debug: 4.3.5 + espree: 9.6.1 + globals: 13.24.0 + ignore: 5.3.1 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@8.57.0': {} + + '@humanwhocodes/config-array@0.11.14': + dependencies: + '@humanwhocodes/object-schema': 2.0.3 + debug: 4.3.5 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/object-schema@2.0.3': {} + + '@istanbuljs/load-nyc-config@1.1.0': + dependencies: + camelcase: 5.3.1 + find-up: 4.1.0 + get-package-type: 0.1.0 + js-yaml: 3.14.1 + resolve-from: 5.0.0 + + '@istanbuljs/schema@0.1.3': {} + + '@jest/console@29.7.0': + dependencies: + '@jest/types': 29.6.3 + '@types/node': 20.14.1 + chalk: 4.1.2 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + slash: 3.0.0 + + '@jest/core@29.7.0': + dependencies: + '@jest/console': 29.7.0 + '@jest/reporters': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.14.1 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + ci-info: 3.9.0 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-changed-files: 29.7.0 + jest-config: 29.7.0(@types/node@20.14.1) + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-resolve-dependencies: 29.7.0 + jest-runner: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + jest-watcher: 29.7.0 + micromatch: 4.0.7 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-ansi: 6.0.1 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + - ts-node + + '@jest/environment@29.7.0': + dependencies: + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.14.1 + jest-mock: 29.7.0 + + '@jest/expect-utils@29.7.0': + dependencies: + jest-get-type: 29.6.3 + + '@jest/expect@29.7.0': + dependencies: + expect: 29.7.0 + jest-snapshot: 29.7.0 + transitivePeerDependencies: + - supports-color + + '@jest/fake-timers@29.7.0': + dependencies: + '@jest/types': 29.6.3 + '@sinonjs/fake-timers': 10.3.0 + '@types/node': 20.14.1 + jest-message-util: 29.7.0 + jest-mock: 29.7.0 + jest-util: 29.7.0 + + '@jest/globals@29.7.0': + dependencies: + '@jest/environment': 29.7.0 + '@jest/expect': 29.7.0 + '@jest/types': 29.6.3 + jest-mock: 29.7.0 + transitivePeerDependencies: + - supports-color + + '@jest/reporters@29.7.0': + dependencies: + '@bcoe/v8-coverage': 0.2.3 + '@jest/console': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@jridgewell/trace-mapping': 0.3.25 + '@types/node': 20.14.1 + chalk: 4.1.2 + collect-v8-coverage: 1.0.2 + exit: 0.1.2 + glob: 7.2.3 + graceful-fs: 4.2.11 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-instrument: 6.0.2 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 4.0.1 + istanbul-reports: 3.1.7 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + jest-worker: 29.7.0 + slash: 3.0.0 + string-length: 4.0.2 + strip-ansi: 6.0.1 + v8-to-istanbul: 9.2.0 + transitivePeerDependencies: + - supports-color + + '@jest/schemas@29.6.3': + dependencies: + '@sinclair/typebox': 0.27.8 + + '@jest/source-map@29.6.3': + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + callsites: 3.1.0 + graceful-fs: 4.2.11 + + '@jest/test-result@29.7.0': + dependencies: + '@jest/console': 29.7.0 + '@jest/types': 29.6.3 + '@types/istanbul-lib-coverage': 2.0.6 + collect-v8-coverage: 1.0.2 + + '@jest/test-sequencer@29.7.0': + dependencies: + '@jest/test-result': 29.7.0 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + slash: 3.0.0 + + '@jest/transform@29.7.0': + dependencies: + '@babel/core': 7.24.6 + '@jest/types': 29.6.3 + '@jridgewell/trace-mapping': 0.3.25 + babel-plugin-istanbul: 6.1.1 + chalk: 4.1.2 + convert-source-map: 2.0.0 + fast-json-stable-stringify: 2.1.0 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-regex-util: 29.6.3 + jest-util: 29.7.0 + micromatch: 4.0.7 + pirates: 4.0.6 + slash: 3.0.0 + write-file-atomic: 4.0.2 + transitivePeerDependencies: + - supports-color + + '@jest/types@29.6.3': + dependencies: + '@jest/schemas': 29.6.3 + '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-reports': 3.0.4 + '@types/node': 20.14.1 + '@types/yargs': 17.0.32 + chalk: 4.1.2 + + '@jridgewell/gen-mapping@0.3.5': + dependencies: + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/trace-mapping': 0.3.25 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/set-array@1.2.1': {} + + '@jridgewell/sourcemap-codec@1.4.15': {} + + '@jridgewell/trace-mapping@0.3.25': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.4.15 + + '@noble/curves@1.4.0': + dependencies: + '@noble/hashes': 1.4.0 + + '@noble/hashes@1.4.0': {} + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.17.1 + + '@scure/base@1.1.6': {} + + '@scure/bip32@1.4.0': + dependencies: + '@noble/curves': 1.4.0 + '@noble/hashes': 1.4.0 + '@scure/base': 1.1.6 + + '@scure/bip39@1.3.0': + dependencies: + '@noble/hashes': 1.4.0 + '@scure/base': 1.1.6 + + '@sinclair/typebox@0.27.8': {} + + '@sindresorhus/is@4.6.0': {} + + '@sinonjs/commons@2.0.0': + dependencies: + type-detect: 4.0.8 + + '@sinonjs/commons@3.0.1': + dependencies: + type-detect: 4.0.8 + + '@sinonjs/fake-timers@10.3.0': + dependencies: + '@sinonjs/commons': 3.0.1 + + '@sinonjs/fake-timers@11.2.2': + dependencies: + '@sinonjs/commons': 3.0.1 + + '@sinonjs/samsam@8.0.0': + dependencies: + '@sinonjs/commons': 2.0.0 + lodash.get: 4.4.2 + type-detect: 4.0.8 + + '@sinonjs/text-encoding@0.7.2': {} + + '@szmarczak/http-timer@4.0.6': + dependencies: + defer-to-connect: 2.0.1 + + '@types/babel__core@7.20.5': + dependencies: + '@babel/parser': 7.24.6 + '@babel/types': 7.24.6 + '@types/babel__generator': 7.6.8 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.20.6 + + '@types/babel__generator@7.6.8': + dependencies: + '@babel/types': 7.24.6 + + '@types/babel__template@7.4.4': + dependencies: + '@babel/parser': 7.24.6 + '@babel/types': 7.24.6 + + '@types/babel__traverse@7.20.6': + dependencies: + '@babel/types': 7.24.6 + + '@types/cacheable-request@6.0.3': + dependencies: + '@types/http-cache-semantics': 4.0.4 + '@types/keyv': 3.1.4 + '@types/node': 20.14.1 + '@types/responselike': 1.0.3 + + '@types/chai@4.3.16': {} + + '@types/graceful-fs@4.1.9': + dependencies: + '@types/node': 20.14.1 + + '@types/http-cache-semantics@4.0.4': {} + + '@types/istanbul-lib-coverage@2.0.6': {} + + '@types/istanbul-lib-report@3.0.3': + dependencies: + '@types/istanbul-lib-coverage': 2.0.6 + + '@types/istanbul-reports@3.0.4': + dependencies: + '@types/istanbul-lib-report': 3.0.3 + + '@types/jest@29.5.12': + dependencies: + expect: 29.7.0 + pretty-format: 29.7.0 + + '@types/json5@0.0.29': {} + + '@types/keyv@3.1.4': + dependencies: + '@types/node': 20.14.1 + + '@types/mocha@10.0.6': {} + + '@types/node@20.14.1': + dependencies: + undici-types: 5.26.5 + + '@types/responselike@1.0.3': + dependencies: + '@types/node': 20.14.1 + + '@types/stack-utils@2.0.3': {} + + '@types/yargs-parser@21.0.3': {} + + '@types/yargs@17.0.32': + dependencies: + '@types/yargs-parser': 21.0.3 + + '@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5)': + dependencies: + '@typescript-eslint/scope-manager': 7.12.0 + '@typescript-eslint/types': 7.12.0 + '@typescript-eslint/typescript-estree': 7.12.0(typescript@5.4.5) + '@typescript-eslint/visitor-keys': 7.12.0 + debug: 4.3.5 + eslint: 8.57.0 + optionalDependencies: + typescript: 5.4.5 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@7.12.0': + dependencies: + '@typescript-eslint/types': 7.12.0 + '@typescript-eslint/visitor-keys': 7.12.0 + + '@typescript-eslint/types@7.12.0': {} + + '@typescript-eslint/typescript-estree@7.12.0(typescript@5.4.5)': + dependencies: + '@typescript-eslint/types': 7.12.0 + '@typescript-eslint/visitor-keys': 7.12.0 + debug: 4.3.5 + globby: 11.1.0 + is-glob: 4.0.3 + minimatch: 9.0.4 + semver: 7.6.2 + ts-api-utils: 1.3.0(typescript@5.4.5) + optionalDependencies: + typescript: 5.4.5 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@7.12.0': + dependencies: + '@typescript-eslint/types': 7.12.0 + eslint-visitor-keys: 3.4.3 + + '@ungap/structured-clone@1.2.0': {} + + acorn-jsx@5.3.2(acorn@8.11.3): + dependencies: + acorn: 8.11.3 + + acorn@8.11.3: {} + + ajv@6.12.6: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ansi-colors@4.1.1: {} + + ansi-escapes@4.3.2: + dependencies: + type-fest: 0.21.3 + + ansi-regex@5.0.1: {} + + ansi-styles@3.2.1: + dependencies: + color-convert: 1.9.3 + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@5.2.0: {} + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + argparse@1.0.10: + dependencies: + sprintf-js: 1.0.3 + + argparse@2.0.1: {} + + array-buffer-byte-length@1.0.1: + dependencies: + call-bind: 1.0.7 + is-array-buffer: 3.0.4 + + array-includes@3.1.8: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 + get-intrinsic: 1.2.4 + is-string: 1.0.7 + + array-union@2.1.0: {} + + array.prototype.findlastindex@1.2.5: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + es-shim-unscopables: 1.0.2 + + array.prototype.flat@1.3.2: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-shim-unscopables: 1.0.2 + + array.prototype.flatmap@1.3.2: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-shim-unscopables: 1.0.2 + + arraybuffer.prototype.slice@1.0.3: + dependencies: + array-buffer-byte-length: 1.0.1 + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + is-array-buffer: 3.0.4 + is-shared-array-buffer: 1.0.3 + + assertion-error@2.0.1: {} + + asynckit@0.4.0: {} + + available-typed-arrays@1.0.7: + dependencies: + possible-typed-array-names: 1.0.0 + + axios@1.6.2: + dependencies: + follow-redirects: 1.15.6 + form-data: 4.0.0 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + + babel-jest@29.7.0(@babel/core@7.24.6): + dependencies: + '@babel/core': 7.24.6 + '@jest/transform': 29.7.0 + '@types/babel__core': 7.20.5 + babel-plugin-istanbul: 6.1.1 + babel-preset-jest: 29.6.3(@babel/core@7.24.6) + chalk: 4.1.2 + graceful-fs: 4.2.11 + slash: 3.0.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-istanbul@6.1.1: + dependencies: + '@babel/helper-plugin-utils': 7.24.6 + '@istanbuljs/load-nyc-config': 1.1.0 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-instrument: 5.2.1 + test-exclude: 6.0.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-jest-hoist@29.6.3: + dependencies: + '@babel/template': 7.24.6 + '@babel/types': 7.24.6 + '@types/babel__core': 7.20.5 + '@types/babel__traverse': 7.20.6 + + babel-preset-current-node-syntax@1.0.1(@babel/core@7.24.6): + dependencies: + '@babel/core': 7.24.6 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.6) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.24.6) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.6) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.6) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.6) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.24.6) + + babel-preset-jest@29.6.3(@babel/core@7.24.6): + dependencies: + '@babel/core': 7.24.6 + babel-plugin-jest-hoist: 29.6.3 + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.24.6) + + balanced-match@1.0.2: {} + + binary-extensions@2.3.0: {} + + brace-expansion@1.1.11: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.1: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browser-stdout@1.3.1: {} + + browserslist@4.23.0: + dependencies: + caniuse-lite: 1.0.30001627 + electron-to-chromium: 1.4.789 + node-releases: 2.0.14 + update-browserslist-db: 1.0.16(browserslist@4.23.0) + + bser@2.1.1: + dependencies: + node-int64: 0.4.0 + + buffer-from@1.1.2: {} + + cacheable-lookup@5.0.4: {} + + cacheable-request@7.0.4: + dependencies: + clone-response: 1.0.3 + get-stream: 5.2.0 + http-cache-semantics: 4.1.1 + keyv: 4.5.4 + lowercase-keys: 2.0.0 + normalize-url: 6.1.0 + responselike: 2.0.1 + + call-bind@1.0.7: + dependencies: + es-define-property: 1.0.0 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.4 + set-function-length: 1.2.2 + + callsites@3.1.0: {} + + camelcase@5.3.1: {} + + camelcase@6.3.0: {} + + caniuse-lite@1.0.30001627: {} + + chai@5.1.1: + dependencies: + assertion-error: 2.0.1 + check-error: 2.1.1 + deep-eql: 5.0.2 + loupe: 3.1.1 + pathval: 2.0.0 + + chalk@2.4.2: + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + char-regex@1.0.2: {} + + check-error@2.1.1: {} + + chokidar@3.5.3: + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + + ci-info@3.9.0: {} + + cjs-module-lexer@1.3.1: {} + + cliui@7.0.4: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + clone-response@1.0.3: + dependencies: + mimic-response: 1.0.1 + + co@4.6.0: {} + + collect-v8-coverage@1.0.2: {} + + color-convert@1.9.3: + dependencies: + color-name: 1.1.3 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.3: {} + + color-name@1.1.4: {} + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + concat-map@0.0.1: {} + + convert-source-map@2.0.0: {} + + create-jest@29.7.0(@types/node@20.14.1): + dependencies: + '@jest/types': 29.6.3 + chalk: 4.1.2 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-config: 29.7.0(@types/node@20.14.1) + jest-util: 29.7.0 + prompts: 2.4.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + + cross-spawn@7.0.3: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + data-view-buffer@1.0.1: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 + + data-view-byte-length@1.0.1: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 + + data-view-byte-offset@1.0.0: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 + + debug@3.2.7: + dependencies: + ms: 2.1.3 + + debug@4.3.4(supports-color@8.1.1): + dependencies: + ms: 2.1.2 + optionalDependencies: + supports-color: 8.1.1 + + debug@4.3.5: + dependencies: + ms: 2.1.2 + + decamelize@4.0.0: {} + + decompress-response@6.0.0: + dependencies: + mimic-response: 3.1.0 + + dedent@1.5.3: {} + + deep-eql@5.0.2: {} + + deep-is@0.1.4: {} + + deepmerge@4.3.1: {} + + defer-to-connect@2.0.1: {} + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.0 + es-errors: 1.3.0 + gopd: 1.0.1 + + define-properties@1.2.1: + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + + delayed-stream@1.0.0: {} + + detect-newline@3.1.0: {} + + diff-sequences@29.6.3: {} + + diff@5.0.0: {} + + diff@5.2.0: {} + + dir-glob@3.0.1: + dependencies: + path-type: 4.0.0 + + doctrine@2.1.0: + dependencies: + esutils: 2.0.3 + + doctrine@3.0.0: + dependencies: + esutils: 2.0.3 + + dotenv@16.4.5: {} + + electron-to-chromium@1.4.789: {} + + emittery@0.13.1: {} + + emoji-regex@8.0.0: {} + + end-of-stream@1.4.4: + dependencies: + once: 1.4.0 + + error-ex@1.3.2: + dependencies: + is-arrayish: 0.2.1 + + es-abstract@1.23.3: + dependencies: + array-buffer-byte-length: 1.0.1 + arraybuffer.prototype.slice: 1.0.3 + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 + data-view-buffer: 1.0.1 + data-view-byte-length: 1.0.1 + data-view-byte-offset: 1.0.0 + es-define-property: 1.0.0 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + es-set-tostringtag: 2.0.3 + es-to-primitive: 1.2.1 + function.prototype.name: 1.1.6 + get-intrinsic: 1.2.4 + get-symbol-description: 1.0.2 + globalthis: 1.0.4 + gopd: 1.0.1 + has-property-descriptors: 1.0.2 + has-proto: 1.0.3 + has-symbols: 1.0.3 + hasown: 2.0.2 + internal-slot: 1.0.7 + is-array-buffer: 3.0.4 + is-callable: 1.2.7 + is-data-view: 1.0.1 + is-negative-zero: 2.0.3 + is-regex: 1.1.4 + is-shared-array-buffer: 1.0.3 + is-string: 1.0.7 + is-typed-array: 1.1.13 + is-weakref: 1.0.2 + object-inspect: 1.13.1 + object-keys: 1.1.1 + object.assign: 4.1.5 + regexp.prototype.flags: 1.5.2 + safe-array-concat: 1.1.2 + safe-regex-test: 1.0.3 + string.prototype.trim: 1.2.9 + string.prototype.trimend: 1.0.8 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.2 + typed-array-byte-length: 1.0.1 + typed-array-byte-offset: 1.0.2 + typed-array-length: 1.0.6 + unbox-primitive: 1.0.2 + which-typed-array: 1.1.15 + + es-define-property@1.0.0: + dependencies: + get-intrinsic: 1.2.4 + + es-errors@1.3.0: {} + + es-object-atoms@1.0.0: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.0.3: + dependencies: + get-intrinsic: 1.2.4 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + es-shim-unscopables@1.0.2: + dependencies: + hasown: 2.0.2 + + es-to-primitive@1.2.1: + dependencies: + is-callable: 1.2.7 + is-date-object: 1.0.5 + is-symbol: 1.0.4 + + escalade@3.1.2: {} + + escape-string-regexp@1.0.5: {} + + escape-string-regexp@2.0.0: {} + + escape-string-regexp@4.0.0: {} + + eslint-import-resolver-node@0.3.9: + dependencies: + debug: 3.2.7 + is-core-module: 2.13.1 + resolve: 1.22.8 + transitivePeerDependencies: + - supports-color + + eslint-module-utils@2.8.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0): + dependencies: + debug: 3.2.7 + optionalDependencies: + '@typescript-eslint/parser': 7.12.0(eslint@8.57.0)(typescript@5.4.5) + eslint: 8.57.0 + eslint-import-resolver-node: 0.3.9 + transitivePeerDependencies: + - supports-color + + eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0): + dependencies: + array-includes: 3.1.8 + array.prototype.findlastindex: 1.2.5 + array.prototype.flat: 1.3.2 + array.prototype.flatmap: 1.3.2 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 8.57.0 + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0) + hasown: 2.0.2 + is-core-module: 2.13.1 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 + object.values: 1.2.0 + semver: 6.3.1 + tsconfig-paths: 3.15.0 + optionalDependencies: + '@typescript-eslint/parser': 7.12.0(eslint@8.57.0)(typescript@5.4.5) + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + + eslint-scope@7.2.2: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint@8.57.0: + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@eslint-community/regexpp': 4.10.1 + '@eslint/eslintrc': 2.1.4 + '@eslint/js': 8.57.0 + '@humanwhocodes/config-array': 0.11.14 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + '@ungap/structured-clone': 1.2.0 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.3 + debug: 4.3.5 + doctrine: 3.0.0 + escape-string-regexp: 4.0.0 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.5.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + find-up: 5.0.0 + glob-parent: 6.0.2 + globals: 13.24.0 + graphemer: 1.4.0 + ignore: 5.3.1 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + is-path-inside: 3.0.3 + js-yaml: 4.1.0 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + strip-ansi: 6.0.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + + espree@9.6.1: + dependencies: + acorn: 8.11.3 + acorn-jsx: 5.3.2(acorn@8.11.3) + eslint-visitor-keys: 3.4.3 + + esprima@4.0.1: {} + + esquery@1.5.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + esutils@2.0.3: {} + + eventemitter3@5.0.1: {} + + execa@5.1.1: + dependencies: + cross-spawn: 7.0.3 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + + exit@0.1.2: {} + + expect@29.7.0: + dependencies: + '@jest/expect-utils': 29.7.0 + jest-get-type: 29.6.3 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + + fast-deep-equal@3.1.3: {} + + fast-glob@3.3.2: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.7 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fastq@1.17.1: + dependencies: + reusify: 1.0.4 + + fb-watchman@2.0.2: + dependencies: + bser: 2.1.1 + + file-entry-cache@6.0.1: + dependencies: + flat-cache: 3.2.0 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-up@4.1.0: + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@3.2.0: + dependencies: + flatted: 3.3.1 + keyv: 4.5.4 + rimraf: 3.0.2 + + flat@5.0.2: {} + + flatted@3.3.1: {} + + follow-redirects@1.15.6: {} + + for-each@0.3.3: + dependencies: + is-callable: 1.2.7 + + form-data@4.0.0: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + + fs.realpath@1.0.0: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + function.prototype.name@1.1.6: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + functions-have-names: 1.2.3 + + functions-have-names@1.2.3: {} + + gensync@1.0.0-beta.2: {} + + get-caller-file@2.0.5: {} + + get-func-name@2.0.2: {} + + get-intrinsic@1.2.4: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + has-proto: 1.0.3 + has-symbols: 1.0.3 + hasown: 2.0.2 + + get-package-type@0.1.0: {} + + get-stream@5.2.0: + dependencies: + pump: 3.0.0 + + get-stream@6.0.1: {} + + get-symbol-description@1.0.2: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + + glob@8.1.0: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 5.0.1 + once: 1.4.0 + + globals@11.12.0: {} + + globals@13.24.0: + dependencies: + type-fest: 0.20.2 + + globalthis@1.0.4: + dependencies: + define-properties: 1.2.1 + gopd: 1.0.1 + + globby@11.1.0: + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.2 + ignore: 5.3.1 + merge2: 1.4.1 + slash: 3.0.0 + + gopd@1.0.1: + dependencies: + get-intrinsic: 1.2.4 + + got@11.8.6: + dependencies: + '@sindresorhus/is': 4.6.0 + '@szmarczak/http-timer': 4.0.6 + '@types/cacheable-request': 6.0.3 + '@types/responselike': 1.0.3 + cacheable-lookup: 5.0.4 + cacheable-request: 7.0.4 + decompress-response: 6.0.0 + http2-wrapper: 1.0.3 + lowercase-keys: 2.0.0 + p-cancelable: 2.1.1 + responselike: 2.0.1 + + graceful-fs@4.2.11: {} + + graphemer@1.4.0: {} + + has-bigints@1.0.2: {} + + has-flag@3.0.0: {} + + has-flag@4.0.0: {} + + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.0 + + has-proto@1.0.3: {} + + has-symbols@1.0.3: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.0.3 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + he@1.2.0: {} + + html-escaper@2.0.2: {} + + http-cache-semantics@4.1.1: {} + + http2-wrapper@1.0.3: + dependencies: + quick-lru: 5.1.1 + resolve-alpn: 1.2.1 + + human-signals@2.1.0: {} + + ignore@5.3.1: {} + + import-fresh@3.3.0: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + import-local@3.1.0: + dependencies: + pkg-dir: 4.2.0 + resolve-cwd: 3.0.0 + + imurmurhash@0.1.4: {} + + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.4: {} + + internal-slot@1.0.7: + dependencies: + es-errors: 1.3.0 + hasown: 2.0.2 + side-channel: 1.0.6 + + is-array-buffer@3.0.4: + dependencies: + call-bind: 1.0.7 + get-intrinsic: 1.2.4 + + is-arrayish@0.2.1: {} + + is-bigint@1.0.4: + dependencies: + has-bigints: 1.0.2 + + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.3.0 + + is-boolean-object@1.1.2: + dependencies: + call-bind: 1.0.7 + has-tostringtag: 1.0.2 + + is-callable@1.2.7: {} + + is-core-module@2.13.1: + dependencies: + hasown: 2.0.2 + + is-data-view@1.0.1: + dependencies: + is-typed-array: 1.1.13 + + is-date-object@1.0.5: + dependencies: + has-tostringtag: 1.0.2 + + is-extglob@2.1.1: {} + + is-fullwidth-code-point@3.0.0: {} + + is-generator-fn@2.1.0: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-negative-zero@2.0.3: {} + + is-number-object@1.0.7: + dependencies: + has-tostringtag: 1.0.2 + + is-number@7.0.0: {} + + is-path-inside@3.0.3: {} + + is-plain-obj@2.1.0: {} + + is-regex@1.1.4: + dependencies: + call-bind: 1.0.7 + has-tostringtag: 1.0.2 + + is-shared-array-buffer@1.0.3: + dependencies: + call-bind: 1.0.7 + + is-stream@2.0.1: {} + + is-string@1.0.7: + dependencies: + has-tostringtag: 1.0.2 + + is-symbol@1.0.4: + dependencies: + has-symbols: 1.0.3 + + is-typed-array@1.1.13: + dependencies: + which-typed-array: 1.1.15 + + is-unicode-supported@0.1.0: {} + + is-weakref@1.0.2: + dependencies: + call-bind: 1.0.7 + + isarray@2.0.5: {} + + isexe@2.0.0: {} + + istanbul-lib-coverage@3.2.2: {} + + istanbul-lib-instrument@5.2.1: + dependencies: + '@babel/core': 7.24.6 + '@babel/parser': 7.24.6 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.2 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + istanbul-lib-instrument@6.0.2: + dependencies: + '@babel/core': 7.24.6 + '@babel/parser': 7.24.6 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.2 + semver: 7.6.2 + transitivePeerDependencies: + - supports-color + + istanbul-lib-report@3.0.1: + dependencies: + istanbul-lib-coverage: 3.2.2 + make-dir: 4.0.0 + supports-color: 7.2.0 + + istanbul-lib-source-maps@4.0.1: + dependencies: + debug: 4.3.5 + istanbul-lib-coverage: 3.2.2 + source-map: 0.6.1 + transitivePeerDependencies: + - supports-color + + istanbul-reports@3.1.7: + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + + jest-changed-files@29.7.0: + dependencies: + execa: 5.1.1 + jest-util: 29.7.0 + p-limit: 3.1.0 + + jest-circus@29.7.0: + dependencies: + '@jest/environment': 29.7.0 + '@jest/expect': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.14.1 + chalk: 4.1.2 + co: 4.6.0 + dedent: 1.5.3 + is-generator-fn: 2.1.0 + jest-each: 29.7.0 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + p-limit: 3.1.0 + pretty-format: 29.7.0 + pure-rand: 6.1.0 + slash: 3.0.0 + stack-utils: 2.0.6 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + jest-cli@29.7.0(@types/node@20.14.1): + dependencies: + '@jest/core': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + chalk: 4.1.2 + create-jest: 29.7.0(@types/node@20.14.1) + exit: 0.1.2 + import-local: 3.1.0 + jest-config: 29.7.0(@types/node@20.14.1) + jest-util: 29.7.0 + jest-validate: 29.7.0 + yargs: 17.7.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + + jest-config@29.7.0(@types/node@20.14.1): + dependencies: + '@babel/core': 7.24.6 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.24.6) + chalk: 4.1.2 + ci-info: 3.9.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0 + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.7 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 20.14.1 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + jest-diff@29.7.0: + dependencies: + chalk: 4.1.2 + diff-sequences: 29.6.3 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + + jest-docblock@29.7.0: + dependencies: + detect-newline: 3.1.0 + + jest-each@29.7.0: + dependencies: + '@jest/types': 29.6.3 + chalk: 4.1.2 + jest-get-type: 29.6.3 + jest-util: 29.7.0 + pretty-format: 29.7.0 + + jest-environment-node@29.7.0: + dependencies: + '@jest/environment': 29.7.0 + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.14.1 + jest-mock: 29.7.0 + jest-util: 29.7.0 + + jest-get-type@29.6.3: {} + + jest-haste-map@29.7.0: + dependencies: + '@jest/types': 29.6.3 + '@types/graceful-fs': 4.1.9 + '@types/node': 20.14.1 + anymatch: 3.1.3 + fb-watchman: 2.0.2 + graceful-fs: 4.2.11 + jest-regex-util: 29.6.3 + jest-util: 29.7.0 + jest-worker: 29.7.0 + micromatch: 4.0.7 + walker: 1.0.8 + optionalDependencies: + fsevents: 2.3.3 + + jest-leak-detector@29.7.0: + dependencies: + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + + jest-matcher-utils@29.7.0: + dependencies: + chalk: 4.1.2 + jest-diff: 29.7.0 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + + jest-message-util@29.7.0: + dependencies: + '@babel/code-frame': 7.24.6 + '@jest/types': 29.6.3 + '@types/stack-utils': 2.0.3 + chalk: 4.1.2 + graceful-fs: 4.2.11 + micromatch: 4.0.7 + pretty-format: 29.7.0 + slash: 3.0.0 + stack-utils: 2.0.6 + + jest-mock@29.7.0: + dependencies: + '@jest/types': 29.6.3 + '@types/node': 20.14.1 + jest-util: 29.7.0 + + jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): + optionalDependencies: + jest-resolve: 29.7.0 + + jest-regex-util@29.6.3: {} + + jest-resolve-dependencies@29.7.0: + dependencies: + jest-regex-util: 29.6.3 + jest-snapshot: 29.7.0 + transitivePeerDependencies: + - supports-color + + jest-resolve@29.7.0: + dependencies: + chalk: 4.1.2 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-pnp-resolver: 1.2.3(jest-resolve@29.7.0) + jest-util: 29.7.0 + jest-validate: 29.7.0 + resolve: 1.22.8 + resolve.exports: 2.0.2 + slash: 3.0.0 + + jest-runner@29.7.0: + dependencies: + '@jest/console': 29.7.0 + '@jest/environment': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.14.1 + chalk: 4.1.2 + emittery: 0.13.1 + graceful-fs: 4.2.11 + jest-docblock: 29.7.0 + jest-environment-node: 29.7.0 + jest-haste-map: 29.7.0 + jest-leak-detector: 29.7.0 + jest-message-util: 29.7.0 + jest-resolve: 29.7.0 + jest-runtime: 29.7.0 + jest-util: 29.7.0 + jest-watcher: 29.7.0 + jest-worker: 29.7.0 + p-limit: 3.1.0 + source-map-support: 0.5.13 + transitivePeerDependencies: + - supports-color + + jest-runtime@29.7.0: + dependencies: + '@jest/environment': 29.7.0 + '@jest/fake-timers': 29.7.0 + '@jest/globals': 29.7.0 + '@jest/source-map': 29.6.3 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.14.1 + chalk: 4.1.2 + cjs-module-lexer: 1.3.1 + collect-v8-coverage: 1.0.2 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-mock: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + slash: 3.0.0 + strip-bom: 4.0.0 + transitivePeerDependencies: + - supports-color + + jest-snapshot@29.7.0: + dependencies: + '@babel/core': 7.24.6 + '@babel/generator': 7.24.6 + '@babel/plugin-syntax-jsx': 7.24.6(@babel/core@7.24.6) + '@babel/plugin-syntax-typescript': 7.24.6(@babel/core@7.24.6) + '@babel/types': 7.24.6 + '@jest/expect-utils': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.24.6) + chalk: 4.1.2 + expect: 29.7.0 + graceful-fs: 4.2.11 + jest-diff: 29.7.0 + jest-get-type: 29.6.3 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + natural-compare: 1.4.0 + pretty-format: 29.7.0 + semver: 7.6.2 + transitivePeerDependencies: + - supports-color + + jest-util@29.7.0: + dependencies: + '@jest/types': 29.6.3 + '@types/node': 20.14.1 + chalk: 4.1.2 + ci-info: 3.9.0 + graceful-fs: 4.2.11 + picomatch: 2.3.1 + + jest-validate@29.7.0: + dependencies: + '@jest/types': 29.6.3 + camelcase: 6.3.0 + chalk: 4.1.2 + jest-get-type: 29.6.3 + leven: 3.1.0 + pretty-format: 29.7.0 + + jest-watcher@29.7.0: + dependencies: + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.14.1 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + emittery: 0.13.1 + jest-util: 29.7.0 + string-length: 4.0.2 + + jest-worker@29.7.0: + dependencies: + '@types/node': 20.14.1 + jest-util: 29.7.0 + merge-stream: 2.0.0 + supports-color: 8.1.1 + + jest@29.7.0(@types/node@20.14.1): + dependencies: + '@jest/core': 29.7.0 + '@jest/types': 29.6.3 + import-local: 3.1.0 + jest-cli: 29.7.0(@types/node@20.14.1) + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + + js-base64@3.7.7: {} + + js-tokens@4.0.0: {} + + js-yaml@3.14.1: + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + + js-yaml@4.1.0: + dependencies: + argparse: 2.0.1 + + jsesc@2.5.2: {} + + json-buffer@3.0.1: {} + + json-parse-even-better-errors@2.3.1: {} + + json-schema-traverse@0.4.1: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + json5@1.0.2: + dependencies: + minimist: 1.2.8 + + json5@2.2.3: {} + + just-extend@6.2.0: {} + + jwt-decode@4.0.0: {} + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + kleur@3.0.3: {} + + leven@3.1.0: {} + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + lines-and-columns@1.2.4: {} + + locate-path@5.0.0: + dependencies: + p-locate: 4.1.0 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.get@4.4.2: {} + + lodash.merge@4.6.2: {} + + log-symbols@4.1.0: + dependencies: + chalk: 4.1.2 + is-unicode-supported: 0.1.0 + + loupe@3.1.1: + dependencies: + get-func-name: 2.0.2 + + lowercase-keys@2.0.0: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + make-dir@4.0.0: + dependencies: + semver: 7.6.2 + + makeerror@1.0.12: + dependencies: + tmpl: 1.0.5 + + merge-stream@2.0.0: {} + + merge2@1.4.1: {} + + micromatch@4.0.7: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mimic-fn@2.1.0: {} + + mimic-response@1.0.1: {} + + mimic-response@3.1.0: {} + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.11 + + minimatch@5.0.1: + dependencies: + brace-expansion: 2.0.1 + + minimatch@9.0.4: + dependencies: + brace-expansion: 2.0.1 + + minimist@1.2.8: {} + + mocha@10.4.0: + dependencies: + ansi-colors: 4.1.1 + browser-stdout: 1.3.1 + chokidar: 3.5.3 + debug: 4.3.4(supports-color@8.1.1) + diff: 5.0.0 + escape-string-regexp: 4.0.0 + find-up: 5.0.0 + glob: 8.1.0 + he: 1.2.0 + js-yaml: 4.1.0 + log-symbols: 4.1.0 + minimatch: 5.0.1 + ms: 2.1.3 + serialize-javascript: 6.0.0 + strip-json-comments: 3.1.1 + supports-color: 8.1.1 + workerpool: 6.2.1 + yargs: 16.2.0 + yargs-parser: 20.2.4 + yargs-unparser: 2.0.0 + + ms@2.1.2: {} + + ms@2.1.3: {} + + natural-compare@1.4.0: {} + + nise@6.0.0: + dependencies: + '@sinonjs/commons': 3.0.1 + '@sinonjs/fake-timers': 11.2.2 + '@sinonjs/text-encoding': 0.7.2 + just-extend: 6.2.0 + path-to-regexp: 6.2.2 + + node-int64@0.4.0: {} + + node-releases@2.0.14: {} + + normalize-path@3.0.0: {} + + normalize-url@6.1.0: {} + + npm-run-path@4.0.1: + dependencies: + path-key: 3.1.1 + + object-inspect@1.13.1: {} + + object-keys@1.1.1: {} + + object.assign@4.1.5: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + has-symbols: 1.0.3 + object-keys: 1.1.1 + + object.fromentries@2.0.8: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 + + object.groupby@1.0.3: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + + object.values@1.2.0: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + onetime@5.1.2: + dependencies: + mimic-fn: 2.1.0 + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + p-cancelable@2.1.1: {} + + p-limit@2.3.0: + dependencies: + p-try: 2.2.0 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@4.1.0: + dependencies: + p-limit: 2.3.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + p-try@2.2.0: {} + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.24.6 + error-ex: 1.3.2 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + + path-exists@4.0.0: {} + + path-is-absolute@1.0.1: {} + + path-key@3.1.1: {} + + path-parse@1.0.7: {} + + path-to-regexp@6.2.2: {} + + path-type@4.0.0: {} + + pathval@2.0.0: {} + + picocolors@1.0.1: {} + + picomatch@2.3.1: {} + + pirates@4.0.6: {} + + pkg-dir@4.2.0: + dependencies: + find-up: 4.1.0 + + poseidon-lite@0.2.0: {} + + possible-typed-array-names@1.0.0: {} + + prelude-ls@1.2.1: {} + + pretty-format@29.7.0: + dependencies: + '@jest/schemas': 29.6.3 + ansi-styles: 5.2.0 + react-is: 18.3.1 + + prompts@2.4.2: + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 + + proxy-from-env@1.1.0: {} + + pump@3.0.0: + dependencies: + end-of-stream: 1.4.4 + once: 1.4.0 + + punycode@2.3.1: {} + + pure-rand@6.1.0: {} + + queue-microtask@1.2.3: {} + + quick-lru@5.1.1: {} + + randombytes@2.1.0: + dependencies: + safe-buffer: 5.2.1 + + react-is@18.3.1: {} + + readdirp@3.6.0: + dependencies: + picomatch: 2.3.1 + + regexp.prototype.flags@1.5.2: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-errors: 1.3.0 + set-function-name: 2.0.2 + + require-directory@2.1.1: {} + + resolve-alpn@1.2.1: {} + + resolve-cwd@3.0.0: + dependencies: + resolve-from: 5.0.0 + + resolve-from@4.0.0: {} + + resolve-from@5.0.0: {} + + resolve.exports@2.0.2: {} + + resolve@1.22.8: + dependencies: + is-core-module: 2.13.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + responselike@2.0.1: + dependencies: + lowercase-keys: 2.0.0 + + reusify@1.0.4: {} + + rimraf@3.0.2: + dependencies: + glob: 7.2.3 + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + safe-array-concat@1.1.2: + dependencies: + call-bind: 1.0.7 + get-intrinsic: 1.2.4 + has-symbols: 1.0.3 + isarray: 2.0.5 + + safe-buffer@5.2.1: {} + + safe-regex-test@1.0.3: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-regex: 1.1.4 + + semver@6.3.1: {} + + semver@7.6.2: {} + + serialize-javascript@6.0.0: + dependencies: + randombytes: 2.1.0 + + set-function-length@1.2.2: + 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 + + set-function-name@2.0.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + side-channel@1.0.6: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + object-inspect: 1.13.1 + + signal-exit@3.0.7: {} + + sinon@18.0.0: + dependencies: + '@sinonjs/commons': 3.0.1 + '@sinonjs/fake-timers': 11.2.2 + '@sinonjs/samsam': 8.0.0 + diff: 5.2.0 + nise: 6.0.0 + supports-color: 7.2.0 + + sisteransi@1.0.5: {} + + slash@3.0.0: {} + + source-map-support@0.5.13: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map@0.6.1: {} + + sprintf-js@1.0.3: {} + + stack-utils@2.0.6: + dependencies: + escape-string-regexp: 2.0.0 + + string-length@4.0.2: + dependencies: + char-regex: 1.0.2 + strip-ansi: 6.0.1 + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string.prototype.trim@1.2.9: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 + + string.prototype.trimend@1.0.8: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + + string.prototype.trimstart@1.0.8: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-bom@3.0.0: {} + + strip-bom@4.0.0: {} + + strip-final-newline@2.0.0: {} + + strip-json-comments@3.1.1: {} + + supports-color@5.5.0: + dependencies: + has-flag: 3.0.0 + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + test-exclude@6.0.0: + dependencies: + '@istanbuljs/schema': 0.1.3 + glob: 7.2.3 + minimatch: 3.1.2 + + text-table@0.2.0: {} + + tmpl@1.0.5: {} + + to-fast-properties@2.0.0: {} + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + ts-api-utils@1.3.0(typescript@5.4.5): + dependencies: + typescript: 5.4.5 + + tsconfig-paths@3.15.0: + dependencies: + '@types/json5': 0.0.29 + json5: 1.0.2 + minimist: 1.2.8 + strip-bom: 3.0.0 + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + type-detect@4.0.8: {} + + type-fest@0.20.2: {} + + type-fest@0.21.3: {} + + typed-array-buffer@1.0.2: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-typed-array: 1.1.13 + + typed-array-byte-length@1.0.1: + dependencies: + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-proto: 1.0.3 + is-typed-array: 1.1.13 + + typed-array-byte-offset@1.0.2: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-proto: 1.0.3 + is-typed-array: 1.1.13 + + typed-array-length@1.0.6: + dependencies: + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-proto: 1.0.3 + is-typed-array: 1.1.13 + possible-typed-array-names: 1.0.0 + + typescript@5.4.5: {} + + unbox-primitive@1.0.2: + dependencies: + call-bind: 1.0.7 + has-bigints: 1.0.2 + has-symbols: 1.0.3 + which-boxed-primitive: 1.0.2 + + undici-types@5.26.5: {} + + update-browserslist-db@1.0.16(browserslist@4.23.0): + dependencies: + browserslist: 4.23.0 + escalade: 3.1.2 + picocolors: 1.0.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + v8-to-istanbul@9.2.0: + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + '@types/istanbul-lib-coverage': 2.0.6 + convert-source-map: 2.0.0 + + walker@1.0.8: + dependencies: + makeerror: 1.0.12 + + which-boxed-primitive@1.0.2: + dependencies: + is-bigint: 1.0.4 + is-boolean-object: 1.1.2 + is-number-object: 1.0.7 + is-string: 1.0.7 + is-symbol: 1.0.4 + + which-typed-array@1.1.15: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-tostringtag: 1.0.2 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + word-wrap@1.2.5: {} + + workerpool@6.2.1: {} + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrappy@1.0.2: {} + + write-file-atomic@4.0.2: + dependencies: + imurmurhash: 0.1.4 + signal-exit: 3.0.7 + + y18n@5.0.8: {} + + yallist@3.1.1: {} + + yargs-parser@20.2.4: {} + + yargs-parser@21.1.1: {} + + yargs-unparser@2.0.0: + dependencies: + camelcase: 6.3.0 + decamelize: 4.0.0 + flat: 5.0.2 + is-plain-obj: 2.1.0 + + yargs@16.2.0: + dependencies: + cliui: 7.0.4 + escalade: 3.1.2 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 20.2.4 + + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.1.2 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + + yocto-queue@0.1.0: {} diff --git a/networks/suzuka/suzuka-client/src/tests/hey-partners/tests/typescript-sdk/tsconfig.spec.json b/networks/suzuka/suzuka-client/src/tests/hey-partners/tests/typescript-sdk/tsconfig.spec.json new file mode 100644 index 000000000..32f187982 --- /dev/null +++ b/networks/suzuka/suzuka-client/src/tests/hey-partners/tests/typescript-sdk/tsconfig.spec.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "types": ["jest", "ts-node"] + } + } \ No newline at end of file diff --git a/networks/suzuka/suzuka-client/src/tests/hey-partners/u256/Move.toml b/networks/suzuka/suzuka-client/src/tests/hey-partners/u256/Move.toml new file mode 100644 index 000000000..e8dc5fa5a --- /dev/null +++ b/networks/suzuka/suzuka-client/src/tests/hey-partners/u256/Move.toml @@ -0,0 +1,9 @@ +[package] +name = "U256" +version = "0.3.7" + +[dependencies] +AptosFramework = { git = "https://github.com/aptos-labs/aptos-core.git", subdir = "aptos-move/framework/aptos-framework/", rev = "bbce0f188d7bef08218f1fc1f46bbd3676b5c74b" } + +[addresses] +u256 = "_" diff --git a/networks/suzuka/suzuka-client/src/tests/hey-partners/u256/sources/u256.move b/networks/suzuka/suzuka-client/src/tests/hey-partners/u256/sources/u256.move new file mode 100644 index 000000000..8754b15a5 --- /dev/null +++ b/networks/suzuka/suzuka-client/src/tests/hey-partners/u256/sources/u256.move @@ -0,0 +1,1137 @@ +/// The implementation of large numbers written in Move language. +/// Code derived from original work by Andrew Poelstra +/// +/// Rust Bitcoin Library +/// Written in 2014 by +/// Andrew Poelstra +/// +/// To the extent possible under law, the author(s) have dedicated all +/// copyright and related and neighboring rights to this software to +/// the public domain worldwide. This software is distributed without +/// any warranty. +/// +/// Simplified impl by Parity Team - https://github.com/paritytech/parity-common/blob/master/uint/src/uint.rs +/// +/// Features: +/// * mul +/// * div +/// * add +/// * sub +/// * shift left +/// * shift right +/// * bitwise and, xor, or. +/// * compare +/// * if math overflows the contract crashes. +/// +/// Would be nice to help with the following TODO list: +/// * pow() , sqrt(). +/// * math funcs that don't abort on overflows, but just returns reminders. +/// * Export of low_u128 (see original implementation). +/// * Export of low_u64 (see original implementation). +/// * Gas Optimisation: +/// * We can optimize by replacing bytecode, as far as we know Move VM itself support slices, so probably +/// we can try to replace parts works with (`v0`,`v1`,`v2`,`v3` etc) works. +/// * More? +/// * More tests (see current tests and TODOs i left): +/// * u256_arithmetic_test - https://github.com/paritytech/bigint/blob/master/src/uint.rs#L1338 +/// * More from - https://github.com/paritytech/bigint/blob/master/src/uint.rs +/// * Division: +/// * Could be improved with div_mod_small (current version probably would took a lot of resources for small numbers). +/// * Also could be improved with Knuth, TAOCP, Volume 2, section 4.3.1, Algorithm D (see link to Parity above). +module u256::u256 { + // Errors. + /// When can't cast `U256` to `u128` (e.g. number too large). + const ECAST_OVERFLOW: u64 = 0; + + /// When trying to get or put word into U256 but it's out of index. + const EWORDS_OVERFLOW: u64 = 1; + + /// When math overflows. + const EOVERFLOW: u64 = 2; + + /// When attempted to divide by zero. + const EDIV_BY_ZERO: u64 = 3; + + // Constants. + + /// Max `u64` value. + const U64_MAX: u128 = 18446744073709551615; + + /// Max `u128` value. + const U128_MAX: u128 = 340282366920938463463374607431768211455; + + /// Total words in `U256` (64 * 4 = 256). + const WORDS: u64 = 4; + + /// When both `U256` equal. + const EQUAL: u8 = 0; + + /// When `a` is less than `b`. + const LESS_THAN: u8 = 1; + + /// When `b` is greater than `b`. + const GREATER_THAN: u8 = 2; + + // Data structs. + + /// The `U256` resource. + /// Contains 4 u64 numbers. + struct U256 has copy, drop, store { + v0: u64, + v1: u64, + v2: u64, + v3: u64, + } + + /// Double `U256` used for multiple (to store overflow). + struct DU256 has copy, drop, store { + v0: u64, + v1: u64, + v2: u64, + v3: u64, + v4: u64, + v5: u64, + v6: u64, + v7: u64, + } + + // Public functions. + /// Adds two `U256` and returns sum. + public fun add(a: U256, b: U256): U256 { + let ret = zero(); + let carry = 0u64; + + let i = 0; + while (i < WORDS) { + let a1 = get(&a, i); + let b1 = get(&b, i); + + if (carry != 0) { + let (res1, is_overflow1) = overflowing_add(a1, b1); + let (res2, is_overflow2) = overflowing_add(res1, carry); + put(&mut ret, i, res2); + + carry = 0; + if (is_overflow1) { + carry = carry + 1; + }; + + if (is_overflow2) { + carry = carry + 1; + } + } else { + let (res, is_overflow) = overflowing_add(a1, b1); + put(&mut ret, i, res); + + carry = 0; + if (is_overflow) { + carry = 1; + }; + }; + + i = i + 1; + }; + + assert!(carry == 0, EOVERFLOW); + + ret + } + + /// Convert `U256` to `u128` value if possible (otherwise it aborts). + public fun as_u128(a: U256): u128 { + assert!(a.v2 == 0 && a.v3 == 0, ECAST_OVERFLOW); + ((a.v1 as u128) << 64) + (a.v0 as u128) + } + + /// Convert `U256` to `u64` value if possible (otherwise it aborts). + public fun as_u64(a: U256): u64 { + assert!(a.v1 == 0 && a.v2 == 0 && a.v3 == 0, ECAST_OVERFLOW); + a.v0 + } + + /// Compares two `U256` numbers. + public fun compare(a: &U256, b: &U256): u8 { + let i = WORDS; + while (i > 0) { + i = i - 1; + let a1 = get(a, i); + let b1 = get(b, i); + + if (a1 != b1) { + if (a1 < b1) { + return LESS_THAN + } else { + return GREATER_THAN + } + } + }; + + EQUAL + } + + /// Returns a `U256` from `u64` value. + public fun from_u64(val: u64): U256 { + from_u128((val as u128)) + } + + /// Returns a `U256` from `u128` value. + public fun from_u128(val: u128): U256 { + let (a2, a1) = split_u128(val); + + U256 { + v0: a1, + v1: a2, + v2: 0, + v3: 0, + } + } + + /// Multiples two `U256`. + public fun mul(a: U256, b: U256): U256 { + let ret = DU256 { + v0: 0, + v1: 0, + v2: 0, + v3: 0, + v4: 0, + v5: 0, + v6: 0, + v7: 0, + }; + + let i = 0; + while (i < WORDS) { + let carry = 0u64; + let b1 = get(&b, i); + + let j = 0; + while (j < WORDS) { + let a1 = get(&a, j); + + if (a1 != 0 || carry != 0) { + let (hi, low) = split_u128((a1 as u128) * (b1 as u128)); + + let overflow = { + let existing_low = get_d(&ret, i + j); + let (low, o) = overflowing_add(low, existing_low); + put_d(&mut ret, i + j, low); + if (o) { + 1 + } else { + 0 + } + }; + + carry = { + let existing_hi = get_d(&ret, i + j + 1); + let hi = hi + overflow; + let (hi, o0) = overflowing_add(hi, carry); + let (hi, o1) = overflowing_add(hi, existing_hi); + put_d(&mut ret, i + j + 1, hi); + + if (o0 || o1) { + 1 + } else { + 0 + } + }; + }; + + j = j + 1; + }; + + i = i + 1; + }; + + let (r, overflow) = du256_to_u256(ret); + assert!(!overflow, EOVERFLOW); + r + } + + /// Subtracts two `U256`, returns result. + public fun sub(a: U256, b: U256): U256 { + let ret = zero(); + + let carry = 0u64; + + let i = 0; + while (i < WORDS) { + let a1 = get(&a, i); + let b1 = get(&b, i); + + if (carry != 0) { + let (res1, is_overflow1) = overflowing_sub(a1, b1); + let (res2, is_overflow2) = overflowing_sub(res1, carry); + put(&mut ret, i, res2); + + carry = 0; + if (is_overflow1) { + carry = carry + 1; + }; + + if (is_overflow2) { + carry = carry + 1; + } + } else { + let (res, is_overflow) = overflowing_sub(a1, b1); + put(&mut ret, i, res); + + carry = 0; + if (is_overflow) { + carry = 1; + }; + }; + + i = i + 1; + }; + + assert!(carry == 0, EOVERFLOW); + ret + } + + /// Divide `a` by `b`. + public fun div(a: U256, b: U256): U256 { + let ret = zero(); + + let a_bits = bits(&a); + let b_bits = bits(&b); + + assert!(b_bits != 0, EDIV_BY_ZERO); // DIVIDE BY ZERO. + if (a_bits < b_bits) { + // Immidiatelly return. + return ret + }; + + let shift = a_bits - b_bits; + b = shl(b, (shift as u8)); + + loop { + let cmp = compare(&a, &b); + if (cmp == GREATER_THAN || cmp == EQUAL) { + let index = shift / 64; + let m = get(&ret, index); + let c = m | 1 << ((shift % 64) as u8); + put(&mut ret, index, c); + + a = sub(a, b); + }; + + b = shr(b, 1); + if (shift == 0) { + break + }; + + shift = shift - 1; + }; + + ret + } + + /// Binary xor `a` by `b`. + fun bitxor(a: U256, b: U256): U256 { + let ret = zero(); + + let i = 0; + while (i < WORDS) { + let a1 = get(&a, i); + let b1 = get(&b, i); + put(&mut ret, i, a1 ^ b1); + + i = i + 1; + }; + + ret + } + + /// Binary and `a` by `b`. + fun bitand(a: U256, b: U256): U256 { + let ret = zero(); + + let i = 0; + while (i < WORDS) { + let a1 = get(&a, i); + let b1 = get(&b, i); + put(&mut ret, i, a1 & b1); + + i = i + 1; + }; + + ret + } + + /// Binary or `a` by `b`. + fun bitor(a: U256, b: U256): U256 { + let ret = zero(); + + let i = 0; + while (i < WORDS) { + let a1 = get(&a, i); + let b1 = get(&b, i); + put(&mut ret, i, a1 | b1); + + i = i + 1; + }; + + ret + } + + /// Shift right `a` by `shift`. + public fun shr(a: U256, shift: u8): U256 { + let ret = zero(); + + let word_shift = (shift as u64) / 64; + let bit_shift = (shift as u64) % 64; + + let i = word_shift; + while (i < WORDS) { + let m = get(&a, i) >> (bit_shift as u8); + put(&mut ret, i - word_shift, m); + i = i + 1; + }; + + if (bit_shift > 0) { + let j = word_shift + 1; + while (j < WORDS) { + let m = get(&ret, j - word_shift - 1) + (get(&a, j) << (64 - (bit_shift as u8))); + put(&mut ret, j - word_shift - 1, m); + j = j + 1; + }; + }; + + ret + } + + /// Shift left `a` by `shift`. + public fun shl(a: U256, shift: u8): U256 { + let ret = zero(); + + let word_shift = (shift as u64) / 64; + let bit_shift = (shift as u64) % 64; + + let i = word_shift; + while (i < WORDS) { + let m = get(&a, i - word_shift) << (bit_shift as u8); + put(&mut ret, i, m); + i = i + 1; + }; + + if (bit_shift > 0) { + let j = word_shift + 1; + + while (j < WORDS) { + let m = get(&ret, j) + (get(&a, j - 1 - word_shift) >> (64 - (bit_shift as u8))); + put(&mut ret, j, m); + j = j + 1; + }; + }; + + ret + } + + /// Returns `U256` equals to zero. + public fun zero(): U256 { + U256 { + v0: 0, + v1: 0, + v2: 0, + v3: 0, + } + } + + // Private functions. + /// Get bits used to store `a`. + fun bits(a: &U256): u64 { + let i = 1; + while (i < WORDS) { + let a1 = get(a, WORDS - i); + if (a1 > 0) { + return ((0x40 * (WORDS - i + 1)) - (leading_zeros_u64(a1) as u64)) + }; + + i = i + 1; + }; + + let a1 = get(a, 0); + 0x40 - (leading_zeros_u64(a1) as u64) + } + + /// Get leading zeros of a binary representation of `a`. + fun leading_zeros_u64(a: u64): u8 { + if (a == 0) { + return 64 + }; + + let a1 = a & 0xFFFFFFFF; + let a2 = a >> 32; + + if (a2 == 0) { + let bit = 32; + + while (bit >= 1) { + let b = (a1 >> (bit-1)) & 1; + if (b != 0) { + break + }; + + bit = bit - 1; + }; + + (32 - bit) + 32 + } else { + let bit = 64; + while (bit >= 1) { + let b = (a >> (bit-1)) & 1; + if (b != 0) { + break + }; + bit = bit - 1; + }; + + 64 - bit + } + } + + /// Similar to Rust `overflowing_add`. + /// Returns a tuple of the addition along with a boolean indicating whether an arithmetic overflow would occur. + /// If an overflow would have occurred then the wrapped value is returned. + fun overflowing_add(a: u64, b: u64): (u64, bool) { + let a128 = (a as u128); + let b128 = (b as u128); + + let r = a128 + b128; + if (r > U64_MAX) { + // overflow + let overflow = r - U64_MAX - 1; + ((overflow as u64), true) + } else { + (((a128 + b128) as u64), false) + } + } + + /// Similar to Rust `overflowing_sub`. + /// Returns a tuple of the addition along with a boolean indicating whether an arithmetic overflow would occur. + /// If an overflow would have occurred then the wrapped value is returned. + fun overflowing_sub(a: u64, b: u64): (u64, bool) { + if (a < b) { + let r = b - a; + ((U64_MAX as u64) - r + 1, true) + } else { + (a - b, false) + } + } + + /// Extracts two `u64` from `a` `u128`. + fun split_u128(a: u128): (u64, u64) { + let a1 = ((a >> 64) as u64); + let a2 = ((a & 0xFFFFFFFFFFFFFFFF) as u64); + + (a1, a2) + } + + /// Get word from `a` by index `i`. + public fun get(a: &U256, i: u64): u64 { + if (i == 0) { + a.v0 + } else if (i == 1) { + a.v1 + } else if (i == 2) { + a.v2 + } else if (i == 3) { + a.v3 + } else { + abort EWORDS_OVERFLOW + } + } + + /// Get word from `DU256` by index. + fun get_d(a: &DU256, i: u64): u64 { + if (i == 0) { + a.v0 + } else if (i == 1) { + a.v1 + } else if (i == 2) { + a.v2 + } else if (i == 3) { + a.v3 + } else if (i == 4) { + a.v4 + } else if (i == 5) { + a.v5 + } else if (i == 6) { + a.v6 + } else if (i == 7) { + a.v7 + } else { + abort EWORDS_OVERFLOW + } + } + + /// Put new word `val` into `U256` by index `i`. + fun put(a: &mut U256, i: u64, val: u64) { + if (i == 0) { + a.v0 = val; + } else if (i == 1) { + a.v1 = val; + } else if (i == 2) { + a.v2 = val; + } else if (i == 3) { + a.v3 = val; + } else { + abort EWORDS_OVERFLOW + } + } + + /// Put new word into `DU256` by index `i`. + fun put_d(a: &mut DU256, i: u64, val: u64) { + if (i == 0) { + a.v0 = val; + } else if (i == 1) { + a.v1 = val; + } else if (i == 2) { + a.v2 = val; + } else if (i == 3) { + a.v3 = val; + } else if (i == 4) { + a.v4 = val; + } else if (i == 5) { + a.v5 = val; + } else if (i == 6) { + a.v6 = val; + } else if (i == 7) { + a.v7 = val; + } else { + abort EWORDS_OVERFLOW + } + } + + /// Convert `DU256` to `U256`. + fun du256_to_u256(a: DU256): (U256, bool) { + let b = U256 { + v0: a.v0, + v1: a.v1, + v2: a.v2, + v3: a.v3, + }; + + let overflow = false; + if (a.v4 != 0 || a.v5 != 0 || a.v6 != 0 || a.v7 != 0) { + overflow = true; + }; + + (b, overflow) + } + + // Tests. + #[test] + fun test_get_d() { + let a = DU256 { + v0: 1, + v1: 2, + v2: 3, + v3: 4, + v4: 5, + v5: 6, + v6: 7, + v7: 8, + }; + + assert!(get_d(&a, 0) == 1, 0); + assert!(get_d(&a, 1) == 2, 1); + assert!(get_d(&a, 2) == 3, 2); + assert!(get_d(&a, 3) == 4, 3); + assert!(get_d(&a, 4) == 5, 4); + assert!(get_d(&a, 5) == 6, 5); + assert!(get_d(&a, 6) == 7, 6); + assert!(get_d(&a, 7) == 8, 7); + } + + #[test] + #[expected_failure(abort_code = 1)] + fun test_get_d_overflow() { + let a = DU256 { + v0: 1, + v1: 2, + v2: 3, + v3: 4, + v4: 5, + v5: 6, + v6: 7, + v7: 8, + }; + + get_d(&a, 8); + } + + #[test] + fun test_put_d() { + let a = DU256 { + v0: 1, + v1: 2, + v2: 3, + v3: 4, + v4: 5, + v5: 6, + v6: 7, + v7: 8, + }; + + put_d(&mut a, 0, 10); + put_d(&mut a, 1, 20); + put_d(&mut a, 2, 30); + put_d(&mut a, 3, 40); + put_d(&mut a, 4, 50); + put_d(&mut a, 5, 60); + put_d(&mut a, 6, 70); + put_d(&mut a, 7, 80); + + assert!(get_d(&a, 0) == 10, 0); + assert!(get_d(&a, 1) == 20, 1); + assert!(get_d(&a, 2) == 30, 2); + assert!(get_d(&a, 3) == 40, 3); + assert!(get_d(&a, 4) == 50, 4); + assert!(get_d(&a, 5) == 60, 5); + assert!(get_d(&a, 6) == 70, 6); + assert!(get_d(&a, 7) == 80, 7); + } + + #[test] + #[expected_failure(abort_code = 1)] + fun test_put_d_overflow() { + let a = DU256 { + v0: 1, + v1: 2, + v2: 3, + v3: 4, + v4: 5, + v5: 6, + v6: 7, + v7: 8, + }; + + put_d(&mut a, 8, 0); + } + + #[test] + fun test_du256_to_u256() { + let a = DU256 { + v0: 255, + v1: 100, + v2: 50, + v3: 300, + v4: 0, + v5: 0, + v6: 0, + v7: 0, + }; + + let (m, overflow) = du256_to_u256(a); + assert!(!overflow, 0); + assert!(m.v0 == a.v0, 1); + assert!(m.v1 == a.v1, 2); + assert!(m.v2 == a.v2, 3); + assert!(m.v3 == a.v3, 4); + + a.v4 = 100; + a.v5 = 5; + + let (m, overflow) = du256_to_u256(a); + assert!(overflow, 5); + assert!(m.v0 == a.v0, 6); + assert!(m.v1 == a.v1, 7); + assert!(m.v2 == a.v2, 8); + assert!(m.v3 == a.v3, 9); + } + + #[test] + fun test_get() { + let a = U256 { + v0: 1, + v1: 2, + v2: 3, + v3: 4, + }; + + assert!(get(&a, 0) == 1, 0); + assert!(get(&a, 1) == 2, 1); + assert!(get(&a, 2) == 3, 2); + assert!(get(&a, 3) == 4, 3); + } + + #[test] + #[expected_failure(abort_code = 1)] + fun test_get_aborts() { + let _ = get(&zero(), 4); + } + + #[test] + fun test_put() { + let a = zero(); + put(&mut a, 0, 255); + assert!(get(&a, 0) == 255, 0); + + put(&mut a, 1, (U64_MAX as u64)); + assert!(get(&a, 1) == (U64_MAX as u64), 1); + + put(&mut a, 2, 100); + assert!(get(&a, 2) == 100, 2); + + put(&mut a, 3, 3); + assert!(get(&a, 3) == 3, 3); + + put(&mut a, 2, 0); + assert!(get(&a, 2) == 0, 4); + } + + #[test] + #[expected_failure(abort_code = 1)] + fun test_put_overflow() { + let a = zero(); + put(&mut a, 6, 255); + } + + #[test] + fun test_from_u128() { + let i = 0; + while (i < 1024) { + let big = from_u128(i); + assert!(as_u128(big) == i, 0); + i = i + 1; + }; + } + + #[test] + fun test_add() { + let a = from_u128(1000); + let b = from_u128(500); + + let s = as_u128(add(a, b)); + assert!(s == 1500, 0); + + a = from_u128(U64_MAX); + b = from_u128(U64_MAX); + + s = as_u128(add(a, b)); + assert!(s == (U64_MAX + U64_MAX), 1); + } + + #[test] + #[expected_failure(abort_code = 2)] + fun test_add_overflow() { + let max = (U64_MAX as u64); + + let a = U256 { + v0: max, + v1: max, + v2: max, + v3: max + }; + + let _ = add(a, from_u128(1)); + } + + #[test] + fun test_sub() { + let a = from_u128(1000); + let b = from_u128(500); + + let s = as_u128(sub(a, b)); + assert!(s == 500, 0); + } + + #[test] + #[expected_failure(abort_code = 2)] + fun test_sub_overflow() { + let a = from_u128(0); + let b = from_u128(1); + + let _ = sub(a, b); + } + + #[test] + #[expected_failure(abort_code = 0)] + fun test_too_big_to_cast_to_u128() { + let a = from_u128(U128_MAX); + let b = from_u128(U128_MAX); + + let _ = as_u128(add(a, b)); + } + + #[test] + fun test_overflowing_add() { + let (n, z) = overflowing_add(10, 10); + assert!(n == 20, 0); + assert!(!z, 1); + + (n, z) = overflowing_add((U64_MAX as u64), 1); + assert!(n == 0, 2); + assert!(z, 3); + + (n, z) = overflowing_add((U64_MAX as u64), 10); + assert!(n == 9, 4); + assert!(z, 5); + + (n, z) = overflowing_add(5, 8); + assert!(n == 13, 6); + assert!(!z, 7); + } + + #[test] + fun test_overflowing_sub() { + let (n, z) = overflowing_sub(10, 5); + assert!(n == 5, 0); + assert!(!z, 1); + + (n, z) = overflowing_sub(0, 1); + assert!(n == (U64_MAX as u64), 2); + assert!(z, 3); + + (n, z) = overflowing_sub(10, 10); + assert!(n == 0, 4); + assert!(!z, 5); + } + + #[test] + fun test_split_u128() { + let (a1, a2) = split_u128(100); + assert!(a1 == 0, 0); + assert!(a2 == 100, 1); + + (a1, a2) = split_u128(U64_MAX + 1); + assert!(a1 == 1, 2); + assert!(a2 == 0, 3); + } + + #[test] + fun test_mul() { + let a = from_u128(285); + let b = from_u128(375); + + let c = as_u128(mul(a, b)); + assert!(c == 106875, 0); + + a = from_u128(0); + b = from_u128(1); + + c = as_u128(mul(a, b)); + + assert!(c == 0, 1); + + a = from_u128(U64_MAX); + b = from_u128(2); + + c = as_u128(mul(a, b)); + + assert!(c == 36893488147419103230, 2); + + a = from_u128(U128_MAX); + b = from_u128(U128_MAX); + + let z = mul(a, b); + assert!(bits(&z) == 256, 3); + } + + #[test] + #[expected_failure(abort_code = 2)] + fun test_mul_overflow() { + let max = (U64_MAX as u64); + + let a = U256 { + v0: max, + v1: max, + v2: max, + v3: max, + }; + + let _ = mul(a, from_u128(2)); + } + + #[test] + fun test_zero() { + let a = as_u128(zero()); + assert!(a == 0, 0); + + let a = zero(); + assert!(a.v0 == 0, 1); + assert!(a.v1 == 0, 2); + assert!(a.v2 == 0, 3); + assert!(a.v3 == 0, 4); + } + + #[test] + fun test_or() { + let a = from_u128(0); + let b = from_u128(1); + let c = bitor(a, b); + assert!(as_u128(c) == 1, 0); + + let a = from_u128(0x0f0f0f0f0f0f0f0fu128); + let b = from_u128(0xf0f0f0f0f0f0f0f0u128); + let c = bitor(a, b); + assert!(as_u128(c) == 0xffffffffffffffffu128, 1); + } + + #[test] + fun test_and() { + let a = from_u128(0); + let b = from_u128(1); + let c = bitand(a, b); + assert!(as_u128(c) == 0, 0); + + let a = from_u128(0x0f0f0f0f0f0f0f0fu128); + let b = from_u128(0xf0f0f0f0f0f0f0f0u128); + let c = bitand(a, b); + assert!(as_u128(c) == 0, 1); + + let a = from_u128(0x0f0f0f0f0f0f0f0fu128); + let b = from_u128(0x0f0f0f0f0f0f0f0fu128); + let c = bitand(a, b); + assert!(as_u128(c) == 0x0f0f0f0f0f0f0f0fu128, 1); + } + + #[test] + fun test_xor() { + let a = from_u128(0); + let b = from_u128(1); + let c = bitxor(a, b); + assert!(as_u128(c) == 1, 0); + + let a = from_u128(0x0f0f0f0f0f0f0f0fu128); + let b = from_u128(0xf0f0f0f0f0f0f0f0u128); + let c = bitxor(a, b); + assert!(as_u128(c) == 0xffffffffffffffffu128, 1); + } + + #[test] + fun test_from_u64() { + let a = as_u128(from_u64(100)); + assert!(a == 100, 0); + + // TODO: more tests. + } + + #[test] + fun test_compare() { + let a = from_u128(1000); + let b = from_u128(50); + + let cmp = compare(&a, &b); + assert!(cmp == 2, 0); + + a = from_u128(100); + b = from_u128(100); + cmp = compare(&a, &b); + + assert!(cmp == 0, 1); + + a = from_u128(50); + b = from_u128(75); + + cmp = compare(&a, &b); + assert!(cmp == 1, 2); + } + + #[test] + fun test_leading_zeros_u64() { + let a = leading_zeros_u64(0); + assert!(a == 64, 0); + + let a = leading_zeros_u64(1); + assert!(a == 63, 1); + + // TODO: more tests. + } + + #[test] + fun test_bits() { + let a = bits(&from_u128(0)); + assert!(a == 0, 0); + + a = bits(&from_u128(255)); + assert!(a == 8, 1); + + a = bits(&from_u128(256)); + assert!(a == 9, 2); + + a = bits(&from_u128(300)); + assert!(a == 9, 3); + + a = bits(&from_u128(60000)); + assert!(a == 16, 4); + + a = bits(&from_u128(70000)); + assert!(a == 17, 5); + + let b = from_u64(70000); + let sh = shl(b, 100); + assert!(bits(&sh) == 117, 6); + + let sh = shl(sh, 100); + assert!(bits(&sh) == 217, 7); + + let sh = shl(sh, 100); + assert!(bits(&sh) == 0, 8); + } + + #[test] + fun test_shift_left() { + let a = from_u128(100); + let b = shl(a, 2); + + assert!(as_u128(b) == 400, 0); + + // TODO: more shift left tests. + } + + #[test] + fun test_shift_right() { + let a = from_u128(100); + let b = shr(a, 2); + + assert!(as_u128(b) == 25, 0); + + // TODO: more shift right tests. + } + + #[test] + fun test_div() { + let a = from_u128(100); + let b = from_u128(5); + let d = div(a, b); + + assert!(as_u128(d) == 20, 0); + + let a = from_u128(U64_MAX); + let b = from_u128(U128_MAX); + let d = div(a, b); + assert!(as_u128(d) == 0, 1); + + let a = from_u128(U64_MAX); + let b = from_u128(U128_MAX); + let d = div(a, b); + assert!(as_u128(d) == 0, 2); + + let a = from_u128(U128_MAX); + let b = from_u128(U64_MAX); + let d = div(a, b); + assert!(as_u128(d) == 18446744073709551617, 2); + } + + #[test] + #[expected_failure(abort_code=3)] + fun test_div_by_zero() { + let a = from_u128(1); + let _z = div(a, from_u128(0)); + } + + #[test] + fun test_as_u64() { + let _ = as_u64(from_u64((U64_MAX as u64))); + let _ = as_u64(from_u128(1)); + } + + #[test] + #[expected_failure(abort_code=0)] + fun test_as_u64_overflow() { + let _ = as_u64(from_u128(U128_MAX)); + } +} \ No newline at end of file diff --git a/networks/suzuka/suzuka-client/src/tests/hey-partners/uq64x64/Move.toml b/networks/suzuka/suzuka-client/src/tests/hey-partners/uq64x64/Move.toml new file mode 100644 index 000000000..d4e52a584 --- /dev/null +++ b/networks/suzuka/suzuka-client/src/tests/hey-partners/uq64x64/Move.toml @@ -0,0 +1,9 @@ +[package] +name = "UQ64x64" +version = "0.3.6" + +[dependencies] +AptosFramework = { git = "https://github.com/aptos-labs/aptos-core.git", subdir = "aptos-move/framework/aptos-framework/", rev = "bbce0f188d7bef08218f1fc1f46bbd3676b5c74b" } + +[addresses] +uq64x64 = "_" diff --git a/networks/suzuka/suzuka-client/src/tests/hey-partners/uq64x64/sources/uq64x64.move b/networks/suzuka/suzuka-client/src/tests/hey-partners/uq64x64/sources/uq64x64.move new file mode 100644 index 000000000..1046f9b9f --- /dev/null +++ b/networks/suzuka/suzuka-client/src/tests/hey-partners/uq64x64/sources/uq64x64.move @@ -0,0 +1,114 @@ +/// Implementation of FixedPoint u64 in Move language. +module uq64x64::uq64x64 { + // Error codes. + + /// When divide by zero attempted. + const ERR_DIVIDE_BY_ZERO: u64 = 100; + + // Constants. + + const Q64: u128 = 18446744073709551615; + + /// When a and b are equals. + const EQUAL: u8 = 0; + + /// When a is less than b equals. + const LESS_THAN: u8 = 1; + + /// When a is greater than b. + const GREATER_THAN: u8 = 2; + + /// The resource to store `UQ64x64`. + struct UQ64x64 has copy, store, drop { + v: u128 + } + + /// Encode `u64` to `UQ64x64` + public fun encode(x: u64): UQ64x64 { + let v = (x as u128) * Q64; + UQ64x64{ v } + } + spec encode { + ensures Q64 == MAX_U64; + ensures result.v == x * Q64; + ensures result.v <= MAX_U128; + } + + /// Decode a `UQ64x64` into a `u64` by truncating after the radix point. + public fun decode(uq: UQ64x64): u64 { + ((uq.v / Q64) as u64) + } + spec decode { + ensures result == uq.v / Q64; + } + + /// Get `u128` from UQ64x64 + public fun to_u128(uq: UQ64x64): u128 { + uq.v + } + spec to_u128 { + ensures result == uq.v; + } + + /// Multiply a `UQ64x64` by a `u64`, returning a `UQ64x64` + public fun mul(uq: UQ64x64, y: u64): UQ64x64 { + // vm would direct abort when overflow occured + let v = uq.v * (y as u128); + + UQ64x64{ v } + } + spec mul { + ensures result.v == uq.v * y; + } + + /// Divide a `UQ64x64` by a `u128`, returning a `UQ64x64`. + public fun div(uq: UQ64x64, y: u64): UQ64x64 { + assert!(y != 0, ERR_DIVIDE_BY_ZERO); + + let v = uq.v / (y as u128); + UQ64x64{ v } + } + spec div { + aborts_if y == 0 with ERR_DIVIDE_BY_ZERO; + ensures result.v == uq.v / y; + } + + /// Returns a `UQ64x64` which represents the ratio of the numerator to the denominator. + public fun fraction(numerator: u64, denominator: u64): UQ64x64 { + assert!(denominator != 0, ERR_DIVIDE_BY_ZERO); + + let r = (numerator as u128) * Q64; + let v = r / (denominator as u128); + + UQ64x64{ v } + } + spec fraction { + aborts_if denominator == 0 with ERR_DIVIDE_BY_ZERO; + ensures result.v == numerator * Q64 / denominator; + } + + /// Compare two `UQ64x64` numbers. + public fun compare(left: &UQ64x64, right: &UQ64x64): u8 { + if (left.v == right.v) { + return EQUAL + } else if (left.v < right.v) { + return LESS_THAN + } else { + return GREATER_THAN + } + } + spec compare { + ensures left.v == right.v ==> result == EQUAL; + ensures left.v < right.v ==> result == LESS_THAN; + ensures left.v > right.v ==> result == GREATER_THAN; + } + + /// Check if `UQ64x64` is zero + public fun is_zero(uq: &UQ64x64): bool { + uq.v == 0 + } + spec is_zero { + ensures uq.v == 0 ==> result == true; + ensures uq.v > 0 ==> result == false; + } +} \ No newline at end of file diff --git a/networks/suzuka/suzuka-client/src/tests/mod.rs b/networks/suzuka/suzuka-client/src/tests/mod.rs index 72661ab9c..bf33a3233 100644 --- a/networks/suzuka/suzuka-client/src/tests/mod.rs +++ b/networks/suzuka/suzuka-client/src/tests/mod.rs @@ -556,16 +556,15 @@ pub async fn test_hey_partners() -> Result<(), anyhow::Error> { } async fn test_hey_partners_internal() -> Result<(), anyhow::Error> { - let root: PathBuf = cargo_workspace()?; - let combined_path = if let Ok(path) = env::var("MOVEMENT_SWAP_PATH") { - root.join(path) - }; - - - - println!("Combined path: {:?}", combined_path); - let output = - run_command("/bin/bash", &[format!("{}{}", combined_path, "test.sh").as_str()]).await?; - println!("Output: {}", output); - Ok(output) + let root: PathBuf = cargo_workspace()?; + let additional_path = "networks/suzuka/suzuka-client/src/tests/hey-partners/"; + let combined_path = root.join(additional_path); + + let test = combined_path.to_string_lossy(); + println!("{}", test); + + let output = + run_command("/bin/bash", &[format!("{}{}", test, "test.sh").as_str()]).await?; + println!("Output: {}", output); + Ok(()) } diff --git a/networks/suzuka/suzuka-client/test_result.txt b/networks/suzuka/suzuka-client/test_result.txt index ae9a36ba2..dfa4c03ce 100644 --- a/networks/suzuka/suzuka-client/test_result.txt +++ b/networks/suzuka/suzuka-client/test_result.txt @@ -1,10 +1,3 @@ -{"timestamp":"2024-06-18T17:41:50.973094Z","level":"INFO","fields":{"metrics_scenario":"{\"scenario_id\":0,\"elapse_millli\":0,\"result\":\"Fail\"}"},"target":"exec"} -{"timestamp":"2024-06-18T17:41:50.973094Z","level":"INFO","fields":{"metrics_scenario":"{\"scenario_id\":0,\"elapse_millli\":0,\"result\":\"Fail\"}"},"target":"exec"} -{"timestamp":"2024-06-18T17:41:50.973100Z","level":"INFO","fields":{"metrics_scenario":"{\"scenario_id\":0,\"elapse_millli\":0,\"result\":\"Fail\"}"},"target":"exec"} -{"timestamp":"2024-06-18T17:41:50.973146Z","level":"INFO","fields":{"metrics_scenario":"{\"scenario_id\":0,\"elapse_millli\":0,\"result\":\"Fail\"}"},"target":"exec"} -{"timestamp":"2024-06-18T17:41:50.973152Z","level":"INFO","fields":{"metrics_scenario":"{\"scenario_id\":0,\"elapse_millli\":0,\"result\":\"Fail\"}"},"target":"exec"} -{"timestamp":"2024-06-18T17:41:50.973164Z","level":"INFO","fields":{"metrics_scenario":"{\"scenario_id\":0,\"elapse_millli\":0,\"result\":\"Fail\"}"},"target":"exec"} -{"timestamp":"2024-06-18T17:41:50.973170Z","level":"INFO","fields":{"metrics_scenario":"{\"scenario_id\":0,\"elapse_millli\":0,\"result\":\"Fail\"}"},"target":"exec"} -{"timestamp":"2024-06-18T17:41:50.973194Z","level":"INFO","fields":{"metrics_scenario":"{\"scenario_id\":0,\"elapse_millli\":0,\"result\":\"Fail\"}"},"target":"exec"} -{"timestamp":"2024-06-18T17:41:50.973255Z","level":"INFO","fields":{"metrics_scenario":"{\"scenario_id\":0,\"elapse_millli\":0,\"result\":\"Fail\"}"},"target":"exec"} -{"timestamp":"2024-06-18T17:41:50.973273Z","level":"INFO","fields":{"metrics_scenario":"{\"scenario_id\":0,\"elapse_millli\":0,\"result\":\"Fail\"}"},"target":"exec"} +{"timestamp":"2024-07-01T23:13:06.544875Z","level":"INFO","fields":{"metrics_scenario":"{\"scenario_id\":1,\"elapse_millli\":130932,\"result\":\"Ok\"}"},"target":"exec"} +{"timestamp":"2024-07-01T23:13:06.544942Z","level":"INFO","fields":{"metrics_client_execution":"{\"average_execution_time_milli\":130932}"},"target":"exec"} +{"timestamp":"2024-07-01T23:13:06.545057Z","level":"INFO","fields":{"metrics_average_exec_time":"130932"},"target":"exec"} diff --git a/process-compose/suzuka-full-node/process-compose.build.yml b/process-compose/suzuka-full-node/process-compose.build.yml index 9cca09786..f361d2ff9 100644 --- a/process-compose/suzuka-full-node/process-compose.build.yml +++ b/process-compose/suzuka-full-node/process-compose.build.yml @@ -25,4 +25,4 @@ processes: build-wait-for-celestia-light-node: condition: process_completed_successfully build-suzuka-full-node: - condition: process_completed_successfully + condition: process_completed_successfully \ No newline at end of file diff --git a/protocol-units/bridge/contracts/lib/openzeppelin-contracts b/protocol-units/bridge/contracts/lib/openzeppelin-contracts new file mode 160000 index 000000000..dbb6104ce --- /dev/null +++ b/protocol-units/bridge/contracts/lib/openzeppelin-contracts @@ -0,0 +1 @@ +Subproject commit dbb6104ce834628e473d2173bbc9d47f81a9eec3 diff --git a/protocol-units/bridge/contracts/lib/openzeppelin-contracts-upgradeable b/protocol-units/bridge/contracts/lib/openzeppelin-contracts-upgradeable new file mode 160000 index 000000000..b2542e8df --- /dev/null +++ b/protocol-units/bridge/contracts/lib/openzeppelin-contracts-upgradeable @@ -0,0 +1 @@ +Subproject commit b2542e8df5db336a964b16b3f1014a69286d0c74