diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 34a4a52..353cc5c 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -29,15 +29,18 @@ jobs:
- name: Run Forge fmt
run: |
+ cd eth-contracts
forge fmt --check
id: fmt
- name: Run Forge build
run: |
+ cd eth-contracts
forge build --sizes
id: build
- name: Run Forge tests
run: |
+ cd eth-contracts
forge test -vvv
id: test
diff --git a/.gitmodules b/.gitmodules
index b120396..c4ca283 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,18 @@
[submodule "eth-contracts/lib/forge-std"]
path = eth-contracts/lib/forge-std
url = https://github.com/foundry-rs/forge-std
+[submodule "lib/forge-std"]
+ path = lib/forge-std
+ url = https://github.com/foundry-rs/forge-std
+[submodule "lib/openzeppelin-foundry-upgrades"]
+ path = lib/openzeppelin-foundry-upgrades
+ url = https://github.com/OpenZeppelin/openzeppelin-foundry-upgrades
+[submodule "lib/openzeppelin-contracts-upgradeable"]
+ path = lib/openzeppelin-contracts-upgradeable
+ url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable
+[submodule "eth-contracts/lib/openzeppelin-foundry-upgrades"]
+ path = eth-contracts/lib/openzeppelin-foundry-upgrades
+ url = https://github.com/OpenZeppelin/openzeppelin-foundry-upgrades
+[submodule "eth-contracts/lib/openzeppelin-contracts-upgradeable"]
+ path = eth-contracts/lib/openzeppelin-contracts-upgradeable
+ url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable
diff --git a/.idea/contracts.iml b/.idea/contracts.iml
index e2e1d1f..51e91fe 100644
--- a/.idea/contracts.iml
+++ b/.idea/contracts.iml
@@ -5,6 +5,11 @@
+
+
+
+
+
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
index d9e4aa5..c56669a 100644
--- a/.idea/vcs.xml
+++ b/.idea/vcs.xml
@@ -2,6 +2,6 @@
-
+
\ No newline at end of file
diff --git a/.nvmrc b/.nvmrc
new file mode 100644
index 0000000..b88575e
--- /dev/null
+++ b/.nvmrc
@@ -0,0 +1 @@
+23.7.0
\ No newline at end of file
diff --git a/eth-contracts/.npmrc b/eth-contracts/.npmrc
new file mode 100644
index 0000000..449691b
--- /dev/null
+++ b/eth-contracts/.npmrc
@@ -0,0 +1 @@
+save-exact=true
\ No newline at end of file
diff --git a/eth-contracts/README.md b/eth-contracts/README.md
index 9265b45..1815291 100644
--- a/eth-contracts/README.md
+++ b/eth-contracts/README.md
@@ -1,20 +1,5 @@
## Foundry
-**Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.**
-
-Foundry consists of:
-
-- **Forge**: Ethereum testing framework (like Truffle, Hardhat and DappTools).
-- **Cast**: Swiss army knife for interacting with EVM smart contracts, sending transactions and getting chain data.
-- **Anvil**: Local Ethereum node, akin to Ganache, Hardhat Network.
-- **Chisel**: Fast, utilitarian, and verbose solidity REPL.
-
-## Documentation
-
-https://book.getfoundry.sh/
-
-## Usage
-
### Build
```shell
diff --git a/eth-contracts/lib/openzeppelin-contracts-upgradeable b/eth-contracts/lib/openzeppelin-contracts-upgradeable
new file mode 160000
index 0000000..3d5fa5c
--- /dev/null
+++ b/eth-contracts/lib/openzeppelin-contracts-upgradeable
@@ -0,0 +1 @@
+Subproject commit 3d5fa5c24c411112bab47bec25cfa9ad0af0e6e8
diff --git a/eth-contracts/lib/openzeppelin-foundry-upgrades b/eth-contracts/lib/openzeppelin-foundry-upgrades
new file mode 160000
index 0000000..cbce1e0
--- /dev/null
+++ b/eth-contracts/lib/openzeppelin-foundry-upgrades
@@ -0,0 +1 @@
+Subproject commit cbce1e00305e943aa1661d43f41e5ac72c662b07
diff --git a/eth-contracts/package.json b/eth-contracts/package.json
index 7d9dace..f8e3099 100644
--- a/eth-contracts/package.json
+++ b/eth-contracts/package.json
@@ -8,5 +8,10 @@
"format": "forge fmt"
},
"author": "Abdulla Faraz ",
- "license": "MIT"
+ "license": "MIT",
+ "dependencies": {
+ "@uniswap/sdk-core": "7.5.0",
+ "@uniswap/v3-core": "1.0.1",
+ "@uniswap/v3-periphery": "1.4.4"
+ }
}
diff --git a/eth-contracts/remappings.txt b/eth-contracts/remappings.txt
new file mode 100644
index 0000000..6c4fb35
--- /dev/null
+++ b/eth-contracts/remappings.txt
@@ -0,0 +1,5 @@
+@openzeppelin/contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/
+@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/
+@uniswap/v3-periphery/=node_modules/@uniswap/v3-periphery/
+@uniswap/v3-core/=node_modules/@uniswap/v3-core/
+@uniswap/v3-sdk/=node_modules/@uniswap/v3-sdk/
diff --git a/eth-contracts/script/Counter.s.sol b/eth-contracts/script/Counter.s.sol
deleted file mode 100644
index cdc1fe9..0000000
--- a/eth-contracts/script/Counter.s.sol
+++ /dev/null
@@ -1,19 +0,0 @@
-// SPDX-License-Identifier: UNLICENSED
-pragma solidity ^0.8.13;
-
-import {Script, console} from "forge-std/Script.sol";
-import {Counter} from "../src/Counter.sol";
-
-contract CounterScript is Script {
- Counter public counter;
-
- function setUp() public {}
-
- function run() public {
- vm.startBroadcast();
-
- counter = new Counter();
-
- vm.stopBroadcast();
- }
-}
diff --git a/eth-contracts/src/AbstractMultiWalletAccount.sol b/eth-contracts/src/AbstractMultiWalletAccount.sol
new file mode 100644
index 0000000..d41f378
--- /dev/null
+++ b/eth-contracts/src/AbstractMultiWalletAccount.sol
@@ -0,0 +1,188 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.28;
+
+import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
+import "@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol";
+import "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol";
+import "./lib/AddressSet.sol";
+
+/*
+ * AbstractMultiWalletAccount contract
+ *
+ * This contract is a simple contract that allows a user to deposit funds to an
+ * operator held account and withdraw funds from it.
+ *
+ */
+abstract contract AbstractMultiWalletAccount {
+ /*
+ * The operator of the account (the fund manager if it's a fund)
+ * Operator should not be able to withdraw funds from account.
+ * Operator can swap funds between account after verifying signature.
+ * Operator can swap tokens to other tokens if permission is given by user.
+ */
+ address public operator;
+ /*
+ * The base token of the account (the token in which the account is denominated)
+ * All funds in the account are in base token.
+ */
+ address public baseToken;
+
+ /*
+ * The set of tokens held in this contract
+ */
+ using AddressSet for AddressSet.Set;
+
+ AddressSet.Set tokenSet;
+ /*
+ * The set of depositor who have funds in this contract
+ */
+ AddressSet.Set depositorSet;
+
+ /*
+ * This mapping stores user balances for each token (user => token => amount)
+ */
+ mapping(address => mapping(address => uint256)) public wallets;
+
+ /*
+ * This mapping stores total balances for each token
+ */
+ mapping(address => uint256) public contractTokenBalances;
+
+ /*
+ * this struct is used to pass parameters to swapOnUniswap function
+ */
+ struct SwapOnUniswapParams {
+ address tokenAddressIn;
+ address tokenAddressOut;
+ address swapRouter;
+ uint24 poolFee;
+ uint256 amountIn;
+ uint256 deadline;
+ uint256 amountOutMinimum;
+ uint160 sqrtPriceLimitX96;
+ uint256 estimatedGasFees; // gas fee in base currency
+ }
+
+ event DepositEvent(address from, address tokenAddress, uint256 amountReceived);
+ event WithdrawEvent(address to, address tokenAddress, uint256 amountSent);
+ event SwapSucceeded(uint256 amountOut, address tokenOut, uint256 amountIn, address tokenIn, uint24 poolFee);
+
+ constructor(address _operator, address _baseToken) {
+ operator = _operator;
+ baseToken = _baseToken;
+ tokenSet.insert(_baseToken);
+ }
+
+ function deposit(uint256 amount) external {
+ address depositor = msg.sender;
+
+ IERC20 baseTokenContract = IERC20(baseToken);
+
+ // check allowance
+ uint256 allowance = baseTokenContract.allowance(msg.sender, address(this));
+ require(allowance >= amount, "Allowance is not enough");
+
+ // transfer
+ bool sent = baseTokenContract.transferFrom(depositor, address(this), amount);
+ require(sent, "Failed to deposit funds");
+
+ // update balance
+ wallets[depositor][baseToken] += amount;
+ contractTokenBalances[baseToken] += amount;
+ emit DepositEvent(msg.sender, baseToken, amount);
+ }
+
+ function withdraw(address tokenAddress) external {
+ address withdrawer = msg.sender;
+ uint256 balance = wallets[withdrawer][tokenAddress];
+ require(balance > 0, "Insufficient balance");
+
+ // update balance
+ wallets[withdrawer][tokenAddress] = 0;
+ contractTokenBalances[tokenAddress] -= balance;
+
+ IERC20 tokenContract = IERC20(tokenAddress);
+
+ // transfer
+ bool sent = tokenContract.transfer(withdrawer, balance);
+ require(sent, "Failed to withdraw funds");
+
+ emit WithdrawEvent(withdrawer, tokenAddress, balance);
+ }
+
+ function checkBalance(address user, address tokenAddress) public view returns (uint256) {
+ return wallets[user][tokenAddress];
+ }
+
+ function swapOnUniswap(SwapOnUniswapParams calldata swapParams) external onlyOperator {
+ require(tokenSet.contains(swapParams.tokenAddressIn), "Token not supported");
+ require(contractTokenBalances[swapParams.tokenAddressIn] >= swapParams.amountIn, "Insufficient balance");
+
+ ISwapRouter swapRouter = ISwapRouter(swapParams.swapRouter);
+
+ uint256 amountInAfterFee = swapParams.amountIn - swapParams.estimatedGasFees;
+
+ ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({
+ tokenIn: swapParams.tokenAddressIn,
+ tokenOut: swapParams.tokenAddressOut,
+ fee: swapParams.poolFee,
+ recipient: address(this),
+ deadline: block.timestamp + swapParams.deadline,
+ amountIn: amountInAfterFee,
+ amountOutMinimum: swapParams.amountOutMinimum,
+ sqrtPriceLimitX96: swapParams.sqrtPriceLimitX96
+ });
+
+ uint256 amountOut = swapRouter.exactInputSingle(params);
+ require(amountOut >= swapParams.amountOutMinimum, "Uniswap swap failed");
+
+ uint256 depositorCount = depositorSet.size();
+ address[] memory depositors = new address[](depositorCount);
+ depositors = depositorSet.values();
+
+ uint256 contractTokenBalance = contractTokenBalances[swapParams.tokenAddressIn];
+
+ for (uint256 i = 0; i < depositorCount; i++) {
+ address depositor = depositors[i];
+ uint256 balance = wallets[depositor][swapParams.tokenAddressIn];
+ if (balance > 0) {
+ // deduct tokenIn from users who have tokenIn
+ uint256 depositorShare = (balance / contractTokenBalance);
+ wallets[depositor][swapParams.tokenAddressIn] -= depositorShare * swapParams.amountIn;
+ // update tokenOut balance for users
+ wallets[depositor][swapParams.tokenAddressOut] += depositorShare * amountOut;
+ }
+ }
+ // update contractTokenBalances
+ contractTokenBalances[swapParams.tokenAddressIn] -= swapParams.amountIn;
+
+ // add tokenOut to tokenSet
+ tokenSet.insert(swapParams.tokenAddressOut);
+
+ // update contractTokenBalances
+ contractTokenBalances[swapParams.tokenAddressOut] += amountOut;
+
+ // emit event
+ emit SwapSucceeded(
+ amountOut, swapParams.tokenAddressOut, swapParams.amountIn, swapParams.tokenAddressIn, swapParams.poolFee
+ );
+ }
+
+ modifier onlyOperator() {
+ require(msg.sender == operator, "Only operator can call this function");
+ _;
+ }
+
+ function receiveEthBalance() external payable onlyOperator {}
+
+ receive() external payable onlyOperator {}
+
+ fallback() external payable onlyOperator {}
+
+ function withdrawEthBalance() external onlyOperator {
+ uint256 balance = address(this).balance;
+ address caller = msg.sender;
+ (bool sent, bytes memory data) = caller.call{value: balance}("");
+ require(sent, "Failed to send Ether");
+ }
+}
diff --git a/eth-contracts/src/Counter.sol b/eth-contracts/src/Counter.sol
deleted file mode 100644
index aded799..0000000
--- a/eth-contracts/src/Counter.sol
+++ /dev/null
@@ -1,14 +0,0 @@
-// SPDX-License-Identifier: UNLICENSED
-pragma solidity ^0.8.13;
-
-contract Counter {
- uint256 public number;
-
- function setNumber(uint256 newNumber) public {
- number = newNumber;
- }
-
- function increment() public {
- number++;
- }
-}
diff --git a/eth-contracts/src/MultiWalletAccount.sol b/eth-contracts/src/MultiWalletAccount.sol
new file mode 100644
index 0000000..4c887ea
--- /dev/null
+++ b/eth-contracts/src/MultiWalletAccount.sol
@@ -0,0 +1,8 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.28;
+
+import {AbstractMultiWalletAccount} from "./AbstractMultiWalletAccount.sol";
+
+contract MultiWalletAccount is AbstractMultiWalletAccount {
+ constructor(address _operator, address _baseToken) AbstractMultiWalletAccount(_operator, _baseToken) {}
+}
diff --git a/eth-contracts/src/lib/AddressSet.sol b/eth-contracts/src/lib/AddressSet.sol
new file mode 100644
index 0000000..700606c
--- /dev/null
+++ b/eth-contracts/src/lib/AddressSet.sol
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.28;
+
+// Copyright (c), 2019 Rob Hitchens
+
+library AddressSet {
+ struct Set {
+ mapping(address => uint256) keyPointers;
+ address[] keyList;
+ }
+
+ function insert(Set storage self, address key) internal {
+ require(key != address(0), "UnorderedKeySet(100) - Key cannot be 0x0");
+ require(!contains(self, key), "UnorderedAddressSet(101) - Address (key) already exists in the set.");
+ self.keyList.push(key);
+ self.keyPointers[key] = self.keyList.length - 1;
+ }
+
+ function remove(Set storage self, address key) internal {
+ require(contains(self, key), "UnorderedKeySet(102) - Address (key) does not exist in the set.");
+ address keyToMove = self.keyList[size(self) - 1];
+ uint256 rowToReplace = self.keyPointers[key];
+ self.keyPointers[keyToMove] = rowToReplace;
+ self.keyList[rowToReplace] = keyToMove;
+ delete self.keyPointers[key];
+ self.keyList.pop();
+ }
+
+ function size(Set storage self) internal view returns (uint256) {
+ return (self.keyList.length);
+ }
+
+ function contains(Set storage self, address key) internal view returns (bool) {
+ if (self.keyList.length == 0) return false;
+ return self.keyList[self.keyPointers[key]] == key;
+ }
+
+ function keyAtIndex(Set storage self, uint256 index) internal view returns (address) {
+ return self.keyList[index];
+ }
+
+ function values(Set storage self) internal view returns (address[] memory) {
+ return self.keyList;
+ }
+}
diff --git a/eth-contracts/test/Counter.t.sol b/eth-contracts/test/Counter.t.sol
deleted file mode 100644
index 54b724f..0000000
--- a/eth-contracts/test/Counter.t.sol
+++ /dev/null
@@ -1,24 +0,0 @@
-// SPDX-License-Identifier: UNLICENSED
-pragma solidity ^0.8.13;
-
-import {Test, console} from "forge-std/Test.sol";
-import {Counter} from "../src/Counter.sol";
-
-contract CounterTest is Test {
- Counter public counter;
-
- function setUp() public {
- counter = new Counter();
- counter.setNumber(0);
- }
-
- function test_Increment() public {
- counter.increment();
- assertEq(counter.number(), 1);
- }
-
- function testFuzz_SetNumber(uint256 x) public {
- counter.setNumber(x);
- assertEq(counter.number(), x);
- }
-}
diff --git a/eth-contracts/test/lib/AddressSet.t.sol b/eth-contracts/test/lib/AddressSet.t.sol
new file mode 100644
index 0000000..7c1616f
--- /dev/null
+++ b/eth-contracts/test/lib/AddressSet.t.sol
@@ -0,0 +1,125 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.13;
+
+import {Test, console} from "forge-std/Test.sol";
+import {AddressSet} from "../../src/lib/AddressSet.sol";
+
+contract AddressSetTest is Test {
+ using AddressSet for AddressSet.Set;
+
+ AddressSet.Set tokenSet;
+
+ function setUp() public {}
+
+ function test_shouldBeAbleToInsertItems(address randomAddress) public {
+ if (randomAddress != address(0)) {
+ tokenSet.insert(randomAddress);
+ assert(tokenSet.contains(randomAddress));
+ }
+ }
+
+ /// forge-config: default.allow_internal_expect_revert = true
+ function test_shouldNotBeAbleToInsertZeroAddress() public {
+ vm.expectRevert("UnorderedKeySet(100) - Key cannot be 0x0");
+ tokenSet.insert(address(0));
+ }
+
+ /// forge-config: default.allow_internal_expect_revert = true
+ function test_shouldRevertIfInsertingDuplicateItems(address randomAddress) public {
+ if (randomAddress != address(0)) {
+ vm.expectRevert("UnorderedAddressSet(101) - Address (key) already exists in the set.");
+ tokenSet.insert(randomAddress);
+ tokenSet.insert(randomAddress);
+ }
+ }
+
+ function test_shouldBeAbleToRemoveItems(address randomAddress1, address randomAddress2) public {
+ if (
+ randomAddress1 != randomAddress2 && address(randomAddress1) != address(0)
+ && address(randomAddress2) != address(0)
+ ) {
+ tokenSet.insert(randomAddress1);
+ tokenSet.insert(randomAddress2);
+ tokenSet.remove(randomAddress1);
+ assert(!tokenSet.contains(randomAddress1));
+ assert(tokenSet.contains(randomAddress2));
+ }
+ }
+
+ /// forge-config: default.allow_internal_expect_revert = true
+ function test_shouldRevertIfRemovingNonExistentItems(address randomAddress) public {
+ if (randomAddress != address(0)) {
+ vm.expectRevert("UnorderedKeySet(102) - Address (key) does not exist in the set.");
+ tokenSet.remove(randomAddress);
+ }
+ }
+
+ function test_shouldBeAbleToGetSizeAfterInserting(address randomAddress1, address randomAddress2) public {
+ if (randomAddress1 != randomAddress2 && randomAddress1 != address(0) && randomAddress2 != address(0)) {
+ tokenSet.insert(randomAddress1);
+ tokenSet.insert(randomAddress2);
+ assert(tokenSet.size() == 2);
+ }
+ }
+
+ function test_shouldBeAbleToGetSizeAfterRemoving(
+ address randomAddress1,
+ address randomAddress2,
+ address randomAddress3
+ ) public {
+ if (
+ randomAddress1 != randomAddress2 && randomAddress2 != randomAddress3 && randomAddress1 != randomAddress3
+ && randomAddress1 != address(0) && randomAddress2 != address(0) && randomAddress3 != address(0)
+ ) {
+ tokenSet.insert(randomAddress1);
+ tokenSet.insert(randomAddress2);
+ tokenSet.insert(randomAddress3);
+ tokenSet.remove(randomAddress1);
+ assert(tokenSet.size() == 2);
+ }
+ }
+
+ function test_shouldBeAbleToGetSizeAfterRemovingAllItems(address randomAddress1, address randomAddress2) public {
+ if (randomAddress1 != randomAddress2 && randomAddress1 != address(0) && randomAddress2 != address(0)) {
+ tokenSet.insert(randomAddress1);
+ tokenSet.insert(randomAddress2);
+ tokenSet.remove(randomAddress1);
+ tokenSet.remove(randomAddress2);
+ assert(tokenSet.size() == 0);
+ }
+ }
+
+ function test_shouldReturnTrueIfAddressExists(address randomAddress) public {
+ if (randomAddress != address(0)) {
+ tokenSet.insert(randomAddress);
+ assert(tokenSet.contains(randomAddress));
+ }
+ }
+
+ function test_shouldReturnFalseIfAddressDoesNotExist(address randomAddress1, address randomAddress2) public {
+ if (randomAddress1 != address(0) && randomAddress1 != randomAddress2) {
+ tokenSet.insert(randomAddress1);
+ assert(!tokenSet.contains(randomAddress2));
+ }
+ }
+
+ function test_shouldBeAbleToReferenceByIndex(address randomAddress1, address randomAddress2) public {
+ if (randomAddress1 != randomAddress2 && randomAddress1 != address(0) && randomAddress2 != address(0)) {
+ tokenSet.insert(randomAddress1);
+ tokenSet.insert(randomAddress2);
+ assert(tokenSet.keyAtIndex(0) == randomAddress1);
+ assert(tokenSet.keyAtIndex(1) == randomAddress2);
+ }
+ }
+
+ function test_shouldBeAbleToGetValues(address randomAddress1, address randomAddress2) public {
+ if (randomAddress1 != randomAddress2 && randomAddress1 != address(0) && randomAddress2 != address(0)) {
+ tokenSet.insert(randomAddress1);
+ tokenSet.insert(randomAddress2);
+ address[] memory values = tokenSet.values();
+ assert(values.length == 2);
+ assert(values[0] == randomAddress1);
+ assert(values[1] == randomAddress2);
+ }
+ }
+}
diff --git a/package.json b/package.json
index 1e3d2ac..7ee1711 100644
--- a/package.json
+++ b/package.json
@@ -5,12 +5,15 @@
"scripts": {
"build": "turbo build",
"test": "turbo test",
- "format": "turbo format"
+ "format": "turbo format",
+ "prepare": "husky"
},
"author": "Abdulla Faraz ",
"license": "MIT",
"packageManager": "pnpm@10.4.1",
"devDependencies": {
+ "husky": "9.1.7",
+ "lint-staged": "15.4.3",
"turbo": "2.4.2"
}
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 7477b0f..48e9b55 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -8,14 +8,314 @@ importers:
.:
devDependencies:
+ husky:
+ specifier: 9.1.7
+ version: 9.1.7
+ lint-staged:
+ specifier: 15.4.3
+ version: 15.4.3
turbo:
specifier: 2.4.2
version: 2.4.2
- eth-contracts: {}
+ eth-contracts:
+ dependencies:
+ '@uniswap/sdk-core':
+ specifier: 7.5.0
+ version: 7.5.0
+ '@uniswap/v3-core':
+ specifier: 1.0.1
+ version: 1.0.1
+ '@uniswap/v3-periphery':
+ specifier: 1.4.4
+ version: 1.4.4
packages:
+ '@ethersproject/address@5.7.0':
+ resolution: {integrity: sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==}
+
+ '@ethersproject/bignumber@5.7.0':
+ resolution: {integrity: sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==}
+
+ '@ethersproject/bytes@5.7.0':
+ resolution: {integrity: sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==}
+
+ '@ethersproject/constants@5.7.0':
+ resolution: {integrity: sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==}
+
+ '@ethersproject/keccak256@5.7.0':
+ resolution: {integrity: sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==}
+
+ '@ethersproject/logger@5.7.0':
+ resolution: {integrity: sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==}
+
+ '@ethersproject/rlp@5.7.0':
+ resolution: {integrity: sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==}
+
+ '@ethersproject/strings@5.7.0':
+ resolution: {integrity: sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==}
+
+ '@openzeppelin/contracts@3.4.2-solc-0.7':
+ resolution: {integrity: sha512-W6QmqgkADuFcTLzHL8vVoNBtkwjvQRpYIAom7KiUNoLKghyx3FgH0GBjt8NRvigV1ZmMOBllvE1By1C+bi8WpA==}
+
+ '@uniswap/lib@4.0.1-alpha':
+ resolution: {integrity: sha512-f6UIliwBbRsgVLxIaBANF6w09tYqc6Y/qXdsrbEmXHyFA7ILiKrIwRFXe1yOg8M3cksgVsO9N7yuL2DdCGQKBA==}
+ engines: {node: '>=10'}
+
+ '@uniswap/sdk-core@7.5.0':
+ resolution: {integrity: sha512-4eMbQTu+pEO6CGFG+G9M4ACFPephhfNPpRH40+GGgceHzs73OwQ+5v6Fw5e2JGxr/DEJrS/KcJ2Xjmg/QQ3D6Q==}
+ engines: {node: '>=10'}
+
+ '@uniswap/v2-core@1.0.1':
+ resolution: {integrity: sha512-MtybtkUPSyysqLY2U210NBDeCHX+ltHt3oADGdjqoThZaFRDKwM6k1Nb3F0A3hk5hwuQvytFWhrWHOEq6nVJ8Q==}
+ engines: {node: '>=10'}
+
+ '@uniswap/v3-core@1.0.1':
+ resolution: {integrity: sha512-7pVk4hEm00j9tc71Y9+ssYpO6ytkeI0y7WE9P6UcmNzhxPePwyAxImuhVsTqWK9YFvzgtvzJHi64pBl4jUzKMQ==}
+ engines: {node: '>=10'}
+
+ '@uniswap/v3-periphery@1.4.4':
+ resolution: {integrity: sha512-S4+m+wh8HbWSO3DKk4LwUCPZJTpCugIsHrWR86m/OrUyvSqGDTXKFfc2sMuGXCZrD1ZqO3rhQsKgdWg3Hbb2Kw==}
+ engines: {node: '>=10'}
+
+ ansi-escapes@7.0.0:
+ resolution: {integrity: sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==}
+ engines: {node: '>=18'}
+
+ ansi-regex@6.1.0:
+ resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==}
+ engines: {node: '>=12'}
+
+ ansi-styles@6.2.1:
+ resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
+ engines: {node: '>=12'}
+
+ base64-sol@1.0.1:
+ resolution: {integrity: sha512-ld3cCNMeXt4uJXmLZBHFGMvVpK9KsLVEhPpFRXnvSVAqABKbuNZg/+dsq3NuM+wxFLb/UrVkz7m1ciWmkMfTbg==}
+
+ big.js@5.2.2:
+ resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==}
+
+ bn.js@5.2.1:
+ resolution: {integrity: sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==}
+
+ braces@3.0.3:
+ resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
+ engines: {node: '>=8'}
+
+ chalk@5.4.1:
+ resolution: {integrity: sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==}
+ engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
+
+ cli-cursor@5.0.0:
+ resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==}
+ engines: {node: '>=18'}
+
+ cli-truncate@4.0.0:
+ resolution: {integrity: sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==}
+ engines: {node: '>=18'}
+
+ colorette@2.0.20:
+ resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==}
+
+ commander@13.1.0:
+ resolution: {integrity: sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==}
+ engines: {node: '>=18'}
+
+ cross-spawn@7.0.6:
+ resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
+ engines: {node: '>= 8'}
+
+ debug@4.4.0:
+ resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==}
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
+ decimal.js-light@2.5.1:
+ resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==}
+
+ emoji-regex@10.4.0:
+ resolution: {integrity: sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==}
+
+ environment@1.1.0:
+ resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==}
+ engines: {node: '>=18'}
+
+ eventemitter3@5.0.1:
+ resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==}
+
+ execa@8.0.1:
+ resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==}
+ engines: {node: '>=16.17'}
+
+ fill-range@7.1.1:
+ resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
+ engines: {node: '>=8'}
+
+ get-east-asian-width@1.3.0:
+ resolution: {integrity: sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==}
+ engines: {node: '>=18'}
+
+ get-stream@8.0.1:
+ resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==}
+ engines: {node: '>=16'}
+
+ human-signals@5.0.0:
+ resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==}
+ engines: {node: '>=16.17.0'}
+
+ husky@9.1.7:
+ resolution: {integrity: sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==}
+ engines: {node: '>=18'}
+ hasBin: true
+
+ is-fullwidth-code-point@4.0.0:
+ resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==}
+ engines: {node: '>=12'}
+
+ is-fullwidth-code-point@5.0.0:
+ resolution: {integrity: sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==}
+ engines: {node: '>=18'}
+
+ is-number@7.0.0:
+ resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
+ engines: {node: '>=0.12.0'}
+
+ is-stream@3.0.0:
+ resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+
+ isexe@2.0.0:
+ resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
+
+ js-sha3@0.8.0:
+ resolution: {integrity: sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==}
+
+ jsbi@3.2.5:
+ resolution: {integrity: sha512-aBE4n43IPvjaddScbvWRA2YlTzKEynHzu7MqOyTipdHucf/VxS63ViCjxYRg86M8Rxwbt/GfzHl1kKERkt45fQ==}
+
+ lilconfig@3.1.3:
+ resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==}
+ engines: {node: '>=14'}
+
+ lint-staged@15.4.3:
+ resolution: {integrity: sha512-FoH1vOeouNh1pw+90S+cnuoFwRfUD9ijY2GKy5h7HS3OR7JVir2N2xrsa0+Twc1B7cW72L+88geG5cW4wIhn7g==}
+ engines: {node: '>=18.12.0'}
+ hasBin: true
+
+ listr2@8.2.5:
+ resolution: {integrity: sha512-iyAZCeyD+c1gPyE9qpFu8af0Y+MRtmKOncdGoA2S5EY8iFq99dmmvkNnHiWo+pj0s7yH7l3KPIgee77tKpXPWQ==}
+ engines: {node: '>=18.0.0'}
+
+ log-update@6.1.0:
+ resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==}
+ engines: {node: '>=18'}
+
+ merge-stream@2.0.0:
+ resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
+
+ micromatch@4.0.8:
+ resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
+ engines: {node: '>=8.6'}
+
+ mimic-fn@4.0.0:
+ resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==}
+ engines: {node: '>=12'}
+
+ mimic-function@5.0.1:
+ resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==}
+ engines: {node: '>=18'}
+
+ ms@2.1.3:
+ resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+
+ npm-run-path@5.3.0:
+ resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+
+ onetime@6.0.0:
+ resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==}
+ engines: {node: '>=12'}
+
+ onetime@7.0.0:
+ resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==}
+ engines: {node: '>=18'}
+
+ path-key@3.1.1:
+ resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
+ engines: {node: '>=8'}
+
+ path-key@4.0.0:
+ resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==}
+ engines: {node: '>=12'}
+
+ picomatch@2.3.1:
+ resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
+ engines: {node: '>=8.6'}
+
+ pidtree@0.6.0:
+ resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==}
+ engines: {node: '>=0.10'}
+ hasBin: true
+
+ restore-cursor@5.1.0:
+ resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==}
+ engines: {node: '>=18'}
+
+ rfdc@1.4.1:
+ resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==}
+
+ 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'}
+
+ signal-exit@4.1.0:
+ resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
+ engines: {node: '>=14'}
+
+ slice-ansi@5.0.0:
+ resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==}
+ engines: {node: '>=12'}
+
+ slice-ansi@7.1.0:
+ resolution: {integrity: sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==}
+ engines: {node: '>=18'}
+
+ string-argv@0.3.2:
+ resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==}
+ engines: {node: '>=0.6.19'}
+
+ string-width@7.2.0:
+ resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==}
+ engines: {node: '>=18'}
+
+ strip-ansi@7.1.0:
+ resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==}
+ engines: {node: '>=12'}
+
+ strip-final-newline@3.0.0:
+ resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==}
+ engines: {node: '>=12'}
+
+ tiny-invariant@1.3.3:
+ resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==}
+
+ to-regex-range@5.0.1:
+ resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
+ engines: {node: '>=8.0'}
+
+ toformat@2.0.0:
+ resolution: {integrity: sha512-03SWBVop6nU8bpyZCx7SodpYznbZF5R4ljwNLBcTQzKOD9xuihRo/psX58llS1BMFhhAI08H3luot5GoXJz2pQ==}
+
turbo-darwin-64@2.4.2:
resolution: {integrity: sha512-HFfemyWB60CJtEvVQj9yby5rkkWw9fLAdLtAPGtPQoU3tKh8t/uzCAZKso2aPVbib9vGUuGbPGoGpaRXdVhj5g==}
cpu: [x64]
@@ -50,8 +350,295 @@ packages:
resolution: {integrity: sha512-Qxi0ioQCxMRUCcHKHZkTnYH8e7XCpNfg9QiJcyfWIc+ZXeaCjzV5rCGlbQlTXMAtI8qgfP8fZADv3CFtPwqdPQ==}
hasBin: true
+ which@2.0.2:
+ resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
+ engines: {node: '>= 8'}
+ hasBin: true
+
+ wrap-ansi@9.0.0:
+ resolution: {integrity: sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==}
+ engines: {node: '>=18'}
+
+ yaml@2.7.0:
+ resolution: {integrity: sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==}
+ engines: {node: '>= 14'}
+ hasBin: true
+
snapshots:
+ '@ethersproject/address@5.7.0':
+ dependencies:
+ '@ethersproject/bignumber': 5.7.0
+ '@ethersproject/bytes': 5.7.0
+ '@ethersproject/keccak256': 5.7.0
+ '@ethersproject/logger': 5.7.0
+ '@ethersproject/rlp': 5.7.0
+
+ '@ethersproject/bignumber@5.7.0':
+ dependencies:
+ '@ethersproject/bytes': 5.7.0
+ '@ethersproject/logger': 5.7.0
+ bn.js: 5.2.1
+
+ '@ethersproject/bytes@5.7.0':
+ dependencies:
+ '@ethersproject/logger': 5.7.0
+
+ '@ethersproject/constants@5.7.0':
+ dependencies:
+ '@ethersproject/bignumber': 5.7.0
+
+ '@ethersproject/keccak256@5.7.0':
+ dependencies:
+ '@ethersproject/bytes': 5.7.0
+ js-sha3: 0.8.0
+
+ '@ethersproject/logger@5.7.0': {}
+
+ '@ethersproject/rlp@5.7.0':
+ dependencies:
+ '@ethersproject/bytes': 5.7.0
+ '@ethersproject/logger': 5.7.0
+
+ '@ethersproject/strings@5.7.0':
+ dependencies:
+ '@ethersproject/bytes': 5.7.0
+ '@ethersproject/constants': 5.7.0
+ '@ethersproject/logger': 5.7.0
+
+ '@openzeppelin/contracts@3.4.2-solc-0.7': {}
+
+ '@uniswap/lib@4.0.1-alpha': {}
+
+ '@uniswap/sdk-core@7.5.0':
+ dependencies:
+ '@ethersproject/address': 5.7.0
+ '@ethersproject/bytes': 5.7.0
+ '@ethersproject/keccak256': 5.7.0
+ '@ethersproject/strings': 5.7.0
+ big.js: 5.2.2
+ decimal.js-light: 2.5.1
+ jsbi: 3.2.5
+ tiny-invariant: 1.3.3
+ toformat: 2.0.0
+
+ '@uniswap/v2-core@1.0.1': {}
+
+ '@uniswap/v3-core@1.0.1': {}
+
+ '@uniswap/v3-periphery@1.4.4':
+ dependencies:
+ '@openzeppelin/contracts': 3.4.2-solc-0.7
+ '@uniswap/lib': 4.0.1-alpha
+ '@uniswap/v2-core': 1.0.1
+ '@uniswap/v3-core': 1.0.1
+ base64-sol: 1.0.1
+
+ ansi-escapes@7.0.0:
+ dependencies:
+ environment: 1.1.0
+
+ ansi-regex@6.1.0: {}
+
+ ansi-styles@6.2.1: {}
+
+ base64-sol@1.0.1: {}
+
+ big.js@5.2.2: {}
+
+ bn.js@5.2.1: {}
+
+ braces@3.0.3:
+ dependencies:
+ fill-range: 7.1.1
+
+ chalk@5.4.1: {}
+
+ cli-cursor@5.0.0:
+ dependencies:
+ restore-cursor: 5.1.0
+
+ cli-truncate@4.0.0:
+ dependencies:
+ slice-ansi: 5.0.0
+ string-width: 7.2.0
+
+ colorette@2.0.20: {}
+
+ commander@13.1.0: {}
+
+ cross-spawn@7.0.6:
+ dependencies:
+ path-key: 3.1.1
+ shebang-command: 2.0.0
+ which: 2.0.2
+
+ debug@4.4.0:
+ dependencies:
+ ms: 2.1.3
+
+ decimal.js-light@2.5.1: {}
+
+ emoji-regex@10.4.0: {}
+
+ environment@1.1.0: {}
+
+ eventemitter3@5.0.1: {}
+
+ execa@8.0.1:
+ dependencies:
+ cross-spawn: 7.0.6
+ get-stream: 8.0.1
+ human-signals: 5.0.0
+ is-stream: 3.0.0
+ merge-stream: 2.0.0
+ npm-run-path: 5.3.0
+ onetime: 6.0.0
+ signal-exit: 4.1.0
+ strip-final-newline: 3.0.0
+
+ fill-range@7.1.1:
+ dependencies:
+ to-regex-range: 5.0.1
+
+ get-east-asian-width@1.3.0: {}
+
+ get-stream@8.0.1: {}
+
+ human-signals@5.0.0: {}
+
+ husky@9.1.7: {}
+
+ is-fullwidth-code-point@4.0.0: {}
+
+ is-fullwidth-code-point@5.0.0:
+ dependencies:
+ get-east-asian-width: 1.3.0
+
+ is-number@7.0.0: {}
+
+ is-stream@3.0.0: {}
+
+ isexe@2.0.0: {}
+
+ js-sha3@0.8.0: {}
+
+ jsbi@3.2.5: {}
+
+ lilconfig@3.1.3: {}
+
+ lint-staged@15.4.3:
+ dependencies:
+ chalk: 5.4.1
+ commander: 13.1.0
+ debug: 4.4.0
+ execa: 8.0.1
+ lilconfig: 3.1.3
+ listr2: 8.2.5
+ micromatch: 4.0.8
+ pidtree: 0.6.0
+ string-argv: 0.3.2
+ yaml: 2.7.0
+ transitivePeerDependencies:
+ - supports-color
+
+ listr2@8.2.5:
+ dependencies:
+ cli-truncate: 4.0.0
+ colorette: 2.0.20
+ eventemitter3: 5.0.1
+ log-update: 6.1.0
+ rfdc: 1.4.1
+ wrap-ansi: 9.0.0
+
+ log-update@6.1.0:
+ dependencies:
+ ansi-escapes: 7.0.0
+ cli-cursor: 5.0.0
+ slice-ansi: 7.1.0
+ strip-ansi: 7.1.0
+ wrap-ansi: 9.0.0
+
+ merge-stream@2.0.0: {}
+
+ micromatch@4.0.8:
+ dependencies:
+ braces: 3.0.3
+ picomatch: 2.3.1
+
+ mimic-fn@4.0.0: {}
+
+ mimic-function@5.0.1: {}
+
+ ms@2.1.3: {}
+
+ npm-run-path@5.3.0:
+ dependencies:
+ path-key: 4.0.0
+
+ onetime@6.0.0:
+ dependencies:
+ mimic-fn: 4.0.0
+
+ onetime@7.0.0:
+ dependencies:
+ mimic-function: 5.0.1
+
+ path-key@3.1.1: {}
+
+ path-key@4.0.0: {}
+
+ picomatch@2.3.1: {}
+
+ pidtree@0.6.0: {}
+
+ restore-cursor@5.1.0:
+ dependencies:
+ onetime: 7.0.0
+ signal-exit: 4.1.0
+
+ rfdc@1.4.1: {}
+
+ shebang-command@2.0.0:
+ dependencies:
+ shebang-regex: 3.0.0
+
+ shebang-regex@3.0.0: {}
+
+ signal-exit@4.1.0: {}
+
+ slice-ansi@5.0.0:
+ dependencies:
+ ansi-styles: 6.2.1
+ is-fullwidth-code-point: 4.0.0
+
+ slice-ansi@7.1.0:
+ dependencies:
+ ansi-styles: 6.2.1
+ is-fullwidth-code-point: 5.0.0
+
+ string-argv@0.3.2: {}
+
+ string-width@7.2.0:
+ dependencies:
+ emoji-regex: 10.4.0
+ get-east-asian-width: 1.3.0
+ strip-ansi: 7.1.0
+
+ strip-ansi@7.1.0:
+ dependencies:
+ ansi-regex: 6.1.0
+
+ strip-final-newline@3.0.0: {}
+
+ tiny-invariant@1.3.3: {}
+
+ to-regex-range@5.0.1:
+ dependencies:
+ is-number: 7.0.0
+
+ toformat@2.0.0: {}
+
turbo-darwin-64@2.4.2:
optional: true
@@ -78,3 +665,15 @@ snapshots:
turbo-linux-arm64: 2.4.2
turbo-windows-64: 2.4.2
turbo-windows-arm64: 2.4.2
+
+ which@2.0.2:
+ dependencies:
+ isexe: 2.0.0
+
+ wrap-ansi@9.0.0:
+ dependencies:
+ ansi-styles: 6.2.1
+ string-width: 7.2.0
+ strip-ansi: 7.1.0
+
+ yaml@2.7.0: {}