From c0b094650025c43e683aa33e54e7eefa409d2e76 Mon Sep 17 00:00:00 2001 From: Andrey Date: Fri, 12 Dec 2025 09:31:12 +0400 Subject: [PATCH 01/10] chore: update deps --- .gitmodules | 6 +++--- foundry.lock | 17 +++++++++++++---- lib/forge-std | 2 +- lib/openzeppelin-contracts | 2 +- lib/openzeppelin-contracts-upgradeable | 2 +- 5 files changed, 19 insertions(+), 10 deletions(-) diff --git a/.gitmodules b/.gitmodules index 9296efd5..8f34b8ed 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,9 @@ -[submodule "lib/forge-std"] - path = lib/forge-std - url = https://github.com/foundry-rs/forge-std [submodule "lib/openzeppelin-contracts"] path = lib/openzeppelin-contracts url = https://github.com/OpenZeppelin/openzeppelin-contracts [submodule "lib/openzeppelin-contracts-upgradeable"] path = lib/openzeppelin-contracts-upgradeable url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable +[submodule "lib/forge-std"] + path = lib/forge-std + url = https://github.com/foundry-rs/forge-std diff --git a/foundry.lock b/foundry.lock index 304070aa..977ce843 100644 --- a/foundry.lock +++ b/foundry.lock @@ -1,11 +1,20 @@ { "lib/forge-std": { - "rev": "8e40513d678f392f398620b3ef2b418648b33e89" + "tag": { + "name": "v1.12.0", + "rev": "7117c90c8cf6c68e5acce4f09a6b24715cea4de6" + } }, "lib/openzeppelin-contracts": { - "rev": "dbb6104ce834628e473d2173bbc9d47f81a9eec3" + "tag": { + "name": "v5.5.0", + "rev": "fcbae5394ae8ad52d8e580a3477db99814b9d565" + } }, "lib/openzeppelin-contracts-upgradeable": { - "rev": "723f8cab09cdae1aca9ec9cc1cfa040c2d4b06c1" + "tag": { + "name": "v5.5.0", + "rev": "aa677e9d28ed78fc427ec47ba2baef2030c58e7c" + } } -} +} \ No newline at end of file diff --git a/lib/forge-std b/lib/forge-std index 8e40513d..7117c90c 160000 --- a/lib/forge-std +++ b/lib/forge-std @@ -1 +1 @@ -Subproject commit 8e40513d678f392f398620b3ef2b418648b33e89 +Subproject commit 7117c90c8cf6c68e5acce4f09a6b24715cea4de6 diff --git a/lib/openzeppelin-contracts b/lib/openzeppelin-contracts index dbb6104c..79e49889 160000 --- a/lib/openzeppelin-contracts +++ b/lib/openzeppelin-contracts @@ -1 +1 @@ -Subproject commit dbb6104ce834628e473d2173bbc9d47f81a9eec3 +Subproject commit 79e498895a703ba219e8d5fd90fd4e6e4244f5ba diff --git a/lib/openzeppelin-contracts-upgradeable b/lib/openzeppelin-contracts-upgradeable index 723f8cab..ee17cb93 160000 --- a/lib/openzeppelin-contracts-upgradeable +++ b/lib/openzeppelin-contracts-upgradeable @@ -1 +1 @@ -Subproject commit 723f8cab09cdae1aca9ec9cc1cfa040c2d4b06c1 +Subproject commit ee17cb93fd7999528242025087351e35317cd522 From 65cc5959569892f76e1270da1d18c71f7dcf5fda Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 23 Dec 2025 19:10:20 +0400 Subject: [PATCH 02/10] feat: universal delegator with ui --- .gitmodules | 12 +- foundry.lock | 8 +- lib/openzeppelin-contracts | 2 +- lib/openzeppelin-contracts-upgradeable | 2 +- script/test/README.md | 22 + script/test/UniversalDelegator.s.sol | 99 + script/utils/interfaces/ICreateX.sol | 20 +- spec/delegator/UniversalDelegator.md | 223 ++ .../delegator/NetworkRestakeDelegator.sol | 5 +- .../delegator/UniversalDelegator.sol | 380 ++ .../libraries/UniversalDelegatorIndex.sol | 59 + src/contracts/slasher/VetoSlasher.sol | 3 +- src/interfaces/delegator/IBaseDelegator.sol | 9 +- src/interfaces/delegator/IDelegatorHook.sol | 9 +- .../delegator/IUniversalDelegator.sol | 46 + test/delegator/UniversalDelegator.t.py | 97 + test/delegator/UniversalDelegator.t.sol | 680 ++++ test/integration/SymbioticCoreIntegration.sol | 10 +- .../base/SymbioticCoreBindingsBase.sol | 10 +- .../base/SymbioticCoreInitBase.sol | 6 +- ui/.gitignore | 24 + ui/README.md | 73 + ui/eslint.config.js | 23 + ui/index.html | 13 + ui/package.json | 43 + ui/public/vite.svg | 1 + ui/src/App.css | 42 + ui/src/App.tsx | 5 + ui/src/Providers.tsx | 21 + ui/src/assets/react.svg | 1 + ui/src/contracts/universalDelegator.ts | 289 ++ ui/src/index.css | 8 + ui/src/main.tsx | 13 + .../pages/UniversalDelegatorConfigurator.tsx | 3459 +++++++++++++++++ ui/src/utils/universalDelegatorIndex.ts | 51 + ui/src/web3/config.ts | 28 + ui/tailwind.config.ts | 14 + ui/tsconfig.app.json | 28 + ui/tsconfig.json | 7 + ui/tsconfig.node.json | 26 + ui/vite.config.ts | 8 + 41 files changed, 5825 insertions(+), 54 deletions(-) create mode 100644 script/test/README.md create mode 100644 script/test/UniversalDelegator.s.sol create mode 100644 spec/delegator/UniversalDelegator.md create mode 100644 src/contracts/delegator/UniversalDelegator.sol create mode 100644 src/contracts/libraries/UniversalDelegatorIndex.sol create mode 100644 src/interfaces/delegator/IUniversalDelegator.sol create mode 100644 test/delegator/UniversalDelegator.t.py create mode 100644 test/delegator/UniversalDelegator.t.sol create mode 100644 ui/.gitignore create mode 100644 ui/README.md create mode 100644 ui/eslint.config.js create mode 100644 ui/index.html create mode 100644 ui/package.json create mode 100644 ui/public/vite.svg create mode 100644 ui/src/App.css create mode 100644 ui/src/App.tsx create mode 100644 ui/src/Providers.tsx create mode 100644 ui/src/assets/react.svg create mode 100644 ui/src/contracts/universalDelegator.ts create mode 100644 ui/src/index.css create mode 100644 ui/src/main.tsx create mode 100644 ui/src/pages/UniversalDelegatorConfigurator.tsx create mode 100644 ui/src/utils/universalDelegatorIndex.ts create mode 100644 ui/src/web3/config.ts create mode 100644 ui/tailwind.config.ts create mode 100644 ui/tsconfig.app.json create mode 100644 ui/tsconfig.json create mode 100644 ui/tsconfig.node.json create mode 100644 ui/vite.config.ts diff --git a/.gitmodules b/.gitmodules index 8f34b8ed..7017cc82 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,9 @@ -[submodule "lib/openzeppelin-contracts"] - path = lib/openzeppelin-contracts - url = https://github.com/OpenZeppelin/openzeppelin-contracts -[submodule "lib/openzeppelin-contracts-upgradeable"] - path = lib/openzeppelin-contracts-upgradeable - url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable [submodule "lib/forge-std"] path = lib/forge-std url = https://github.com/foundry-rs/forge-std +[submodule "lib/openzeppelin-contracts-upgradeable"] + path = lib/openzeppelin-contracts-upgradeable + url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable +[submodule "lib/openzeppelin-contracts"] + path = lib/openzeppelin-contracts + url = https://github.com/OpenZeppelin/openzeppelin-contracts diff --git a/foundry.lock b/foundry.lock index 977ce843..dd9fafd6 100644 --- a/foundry.lock +++ b/foundry.lock @@ -7,14 +7,14 @@ }, "lib/openzeppelin-contracts": { "tag": { - "name": "v5.5.0", - "rev": "fcbae5394ae8ad52d8e580a3477db99814b9d565" + "name": "v5.4.0", + "rev": "c64a1edb67b6e3f4a15cca8909c9482ad33a02b0" } }, "lib/openzeppelin-contracts-upgradeable": { "tag": { - "name": "v5.5.0", - "rev": "aa677e9d28ed78fc427ec47ba2baef2030c58e7c" + "name": "v5.4.0", + "rev": "e725abddf1e01cf05ace496e950fc8e243cc7cab" } } } \ No newline at end of file diff --git a/lib/openzeppelin-contracts b/lib/openzeppelin-contracts index 79e49889..c64a1edb 160000 --- a/lib/openzeppelin-contracts +++ b/lib/openzeppelin-contracts @@ -1 +1 @@ -Subproject commit 79e498895a703ba219e8d5fd90fd4e6e4244f5ba +Subproject commit c64a1edb67b6e3f4a15cca8909c9482ad33a02b0 diff --git a/lib/openzeppelin-contracts-upgradeable b/lib/openzeppelin-contracts-upgradeable index ee17cb93..e725abdd 160000 --- a/lib/openzeppelin-contracts-upgradeable +++ b/lib/openzeppelin-contracts-upgradeable @@ -1 +1 @@ -Subproject commit ee17cb93fd7999528242025087351e35317cd522 +Subproject commit e725abddf1e01cf05ace496e950fc8e243cc7cab diff --git a/script/test/README.md b/script/test/README.md new file mode 100644 index 00000000..dc80aff5 --- /dev/null +++ b/script/test/README.md @@ -0,0 +1,22 @@ +# Script Test Harness + +## Universal_Delegator + +### Start Anvil + +```bash +anvil --chain-id 31337 +``` + +Copy the private key of Anvil account #0 from the Anvil output. + +### Deploy a UniversalDelegator for the UI + +```bash +forge script script/test/UniversalDelegator.s.sol:UniversalDelegatorUiSetup \ + --rpc-url http://127.0.0.1:8545 \ + --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 \ + --broadcast +``` + +The script prints `UniversalDelegator instance (proxy)` — paste that address into the UI configurator. diff --git a/script/test/UniversalDelegator.s.sol b/script/test/UniversalDelegator.s.sol new file mode 100644 index 00000000..e92e3f88 --- /dev/null +++ b/script/test/UniversalDelegator.s.sol @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {Script} from "forge-std/Script.sol"; +import {console2} from "forge-std/console2.sol"; + +import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; + +import {Registry} from "../../src/contracts/common/Registry.sol"; +import {UniversalDelegator} from "../../src/contracts/delegator/UniversalDelegator.sol"; + +import {IBaseDelegator} from "../../src/interfaces/delegator/IBaseDelegator.sol"; +import {IUniversalDelegator} from "../../src/interfaces/delegator/IUniversalDelegator.sol"; +import {IEntity} from "../../src/interfaces/common/IEntity.sol"; + +contract MutableRegistry is Registry { + function addEntity(address entity_) external { + _addEntity(entity_); + } +} + +contract MockOptInService { + function isOptedInAt(address, address, uint48, bytes calldata) external pure returns (bool) { + return true; + } + + function isOptedIn(address, address) external pure returns (bool) { + return true; + } +} + +contract MockVaultForUniversalDelegator { + uint256 public activeStake; + uint48 public epochDurationInit; + uint48 public epochDuration; + address public slasher; + + constructor(uint256 activeStake_, uint48 epochDuration_, address slasher_) { + activeStake = activeStake_; + epochDurationInit = uint48(block.timestamp); + epochDuration = epochDuration_; + slasher = slasher_; + } + + function activeStakeAt(uint48, bytes memory) external view returns (uint256) { + return activeStake; + } + + function setActiveStake(uint256 nextActiveStake) external { + activeStake = nextActiveStake; + } +} + +// Local UI setup (anvil): +// forge script script/test/UniversalDelegator.s.sol:UniversalDelegatorUiSetup --rpc-url http://127.0.0.1:8545 --private-key --broadcast +contract UniversalDelegatorUiSetup is Script { + function run() external { + vm.startBroadcast(); + (,, address broadcaster) = vm.readCallers(); + + MutableRegistry registry = new MutableRegistry(); + MockOptInService optInService = new MockOptInService(); + + MockVaultForUniversalDelegator vault = new MockVaultForUniversalDelegator({ + activeStake_: 1000 ether, epochDuration_: 1 days, slasher_: address(0) + }); + registry.addEntity(address(vault)); + + UniversalDelegator implementation = new UniversalDelegator({ + networkRegistry: address(registry), + vaultFactory: address(registry), + operatorVaultOptInService: address(optInService), + operatorNetworkOptInService: address(optInService), + delegatorFactory: address(0), + entityType: 0 + }); + + IBaseDelegator.BaseParams memory baseParams = IBaseDelegator.BaseParams({ + defaultAdminRoleHolder: broadcaster, hook: address(0), hookSetRoleHolder: broadcaster + }); + IUniversalDelegator.InitParams memory initParams = + IUniversalDelegator.InitParams({baseParams: baseParams, curatorRoleHolder: broadcaster}); + + bytes memory initCalldata = + abi.encodeCall(IEntity.initialize, (abi.encode(address(vault), abi.encode(initParams)))); + ERC1967Proxy delegatorProxy = new ERC1967Proxy(address(implementation), initCalldata); + address delegator = address(delegatorProxy); + + vm.stopBroadcast(); + + console2.log("Curator/admin:", broadcaster); + console2.log("Vault (mock):", address(vault)); + console2.log("Vault activeStake:", vault.activeStake()); + console2.log("Vault epochDuration:", uint256(vault.epochDuration())); + console2.log("VaultFactory registry (mock):", address(registry)); + console2.log("UniversalDelegator implementation:", address(implementation)); + console2.log("UniversalDelegator instance (proxy):", delegator); + } +} diff --git a/script/utils/interfaces/ICreateX.sol b/script/utils/interfaces/ICreateX.sol index ad12fcb8..f96b3ef4 100644 --- a/script/utils/interfaces/ICreateX.sol +++ b/script/utils/interfaces/ICreateX.sol @@ -77,12 +77,10 @@ interface ICreateX { payable returns (address newContract); - function deployCreate2AndInit( - bytes memory initCode, - bytes memory data, - Values memory values, - address refundAddress - ) external payable returns (address newContract); + function deployCreate2AndInit(bytes memory initCode, bytes memory data, Values memory values, address refundAddress) + external + payable + returns (address newContract); function deployCreate2AndInit(bytes memory initCode, bytes memory data, Values memory values) external @@ -124,12 +122,10 @@ interface ICreateX { payable returns (address newContract); - function deployCreate3AndInit( - bytes memory initCode, - bytes memory data, - Values memory values, - address refundAddress - ) external payable returns (address newContract); + function deployCreate3AndInit(bytes memory initCode, bytes memory data, Values memory values, address refundAddress) + external + payable + returns (address newContract); function deployCreate3AndInit(bytes memory initCode, bytes memory data, Values memory values) external diff --git a/spec/delegator/UniversalDelegator.md b/spec/delegator/UniversalDelegator.md new file mode 100644 index 00000000..f1b5563e --- /dev/null +++ b/spec/delegator/UniversalDelegator.md @@ -0,0 +1,223 @@ +# Universal Delegator + +`UniversalDelegator` is a `BaseDelegator` implementation that allocates a vault’s stake through a small ordered tree of “slots”. +Slots can be configured to allocate **exclusively** (no overlap) or **shared** (overlap / restaking) between siblings. + +This document describes the contract behavior in `src/contracts/delegator/UniversalDelegator.sol`. + +## Intended depth layout (restaking policy) + +The contract enforces fixed roles by depth (`WrongDepth()`): + +- Depth `0` (`index = 0`): root, **always not shared**. +- Depth `1`: “group” slots (children of root). Can be `isShared = 1`. + - Root is not shared, so depth-1 groups are always isolated from each other. +- Depth `2`: network slots (children of a depth-1 group). Can be assigned to `subnetwork` via `assignNetwork`. + - If the parent group is shared, depth-2 networks **overlap** (restake) between each other. +- Depth `3`: operator slots (children of a depth-2 network). Assigned via `assignOperator`. + - Depth-2 network slots are never shared, so depth-3 operators are always **isolated** within a network. + +## Concepts + +### Slot tree + +- The tree root is the **implicit slot `index = 0`**. +- Every other slot `index > 0` has a **parent slot** and is stored in `slots[index]`. +- Each slot keeps an **ordered list of children** (`children[]`), so sibling ordering is part of the state. + +### Slot indices (`uint96`) + +Slot indices are compact paths encoded into a `uint96` (3 × 32-bit segments). +`src/contracts/libraries/UniversalDelegatorIndex.sol` provides helpers: + +- `createIndex(parentIndex, localIndex)` creates a child index. +- `getParentIndex(index)` returns the parent index. +- `getDepth(index)` returns `0..3` (`0` only for the root `index=0`). + +Practical implications: + +- Max depth is **3** (root + 3 levels of slots). +- A slot at depth **3** cannot have children (index encoding has no further segment). + +### Slot state + +Each slot stores (all checkpointed unless stated): + +- `size`: per-slot cap (upper bound on allocation from its parent). +- `prevSum`: prefix sum of *sizes* of earlier siblings (used only when the parent is not shared). +- `isShared`: if `1`, this slot’s **children** can overlap their allocation (restaking between siblings). +- `pendingFreeCumulative`: cumulative “pending free” amount used to delay re-use of freed stake. +- `children[]`: ordered list of `uint32 localIndex` values. +- `childToLocalIndex`: mapping `(childIndex => position in children[])`. + +## Allocation model + +### Balance vs available + +- `getBalance(0)` / `getBalanceAt(0, t)` is the vault’s active stake: `IVault(vault).activeStake()` / `activeStakeAt(t)`. +- For `index > 0`, `getBalance(index)` / `getBalanceAt(index, t)` equals `getAllocated(index)` / `getAllocatedAt(index, t)`: + the slot’s balance is whatever its parent allocates to it. + +“Available” is balance minus stake currently in the “pending free” window: + +- `getAvailable(index)` and `getAvailableAt(index, t)` subtract the amount scheduled in the last `IVault(vault).epochDuration()`. + +### Child allocation (`getAllocated*`) + +Let: + +- `parentIndex = index.getParentIndex()` +- `availableParent = getAvailable(parentIndex)` (or `getAvailableAt(parentIndex, t)`) +- `cap = slots[index].size` + +In exclusive mode (parent not shared), the child’s effective available is: + +- `childAvailable = saturatingSub(availableParent, slots[index].prevSum)` + +In shared mode (parent shared), the child’s effective available is: + +- `childAvailable = availableParent` + +Finally: + +- `allocated = min(childAvailable, cap)` + +Shared mode means multiple siblings can each reach `allocated == availableParent`, so the **sum of sibling allocations can exceed** the parent’s available stake (restaking/overlap). + +## Slot operations + +### `createSlot(parentIndex, isShared, size)` + +Creates a new child slot under `parentIndex`: + +- Appends a new `localIndex` to `slots[parentIndex].children`. +- Initializes the new slot: + - `prevSum` is set to the current `_getChildrenSize(parentIndex)` (total size of existing children). + - `isShared` is checkpointed on the new slot. + - `size` is set to the provided `size`. + +`isShared = true` is only allowed when creating a depth-1 slot (i.e., `parentIndex` is the root); otherwise it reverts with `WrongDepth()`. + +### `setSize(index, size)` + +Updates a slot’s `size` cap. + +- Increasing size is only allowed when it doesn’t exceed the parent’s currently unallocated capacity (see `NotEnoughAvailable()`). +- Decreasing size below the slot’s current allocation schedules a “pending free” amount on the parent via `pendingFreeCumulative`. +- Updates `prevSum` checkpoints for following siblings using `_syncPrevSums(index)`. + +### `swapSlots(index1, index2)` + +Reorders two sibling slots under the same parent. + +Constraints: + +- Must share the same parent (`NotSameParent()`). +- `index1` must currently appear before `index2` (`WrongOrder()`). +- Both slots must be either allocated or unallocated at the parent level (`NotSameAllocated()`). +- Reverts if the later slot is partially allocated (`PartiallyAllocated()`). + +After swapping: + +- Updates the parent’s `children[]` order and `childToLocalIndex`. +- Pushes a new `prevSum` checkpoint for the moved slot and calls `_syncPrevSums` to update following siblings. + +### `setIsShared(index, isShared)` + +Toggles whether a slot’s **children** allocate in shared mode. + +Rules: + +- Only depth-1 slots can be toggled (`WrongDepth()`), so the root (`index = 0`) is always not shared. +- No-op toggles revert (`IsSharedNotChanged()`). +- For `index > 0`, the slot itself must have zero allocation from its parent (`SlotAllocated()`). + +## Network and operator assignment + +### Networks + +`assignNetwork(index, subnetwork)` assigns a `bytes32 subnetwork` to a slot: + +- `index` must be at depth 2 (`WrongDepth()`). +- A subnetwork can only be assigned once (`NetworkAlreadyAssigned()`). + +`unassignNetwork(subnetwork)` clears the assignment: + +- Reverts if not assigned (`NetworkNotAssigned()`). +- Reverts if the slot still has allocation (`SlotAllocated()`). + +The active slot for a subnetwork is stored historically via `networkToSlot[subnetwork]` checkpoints. + +### Operators + +Operators are assigned *under a specific parent slot* (typically the network’s slot) using: + +- `assignOperator(index, operator)` + +Constraints: + +- `index` must be at depth 3 (`WrongDepth()`). +- The operator must not already be assigned under that parent (`OperatorAlreadyAssigned()`). + +Unassignment: + +- `unassignOperator(parentIndex, operator)` requires the operator’s slot to have zero allocation (`SlotAllocated()`), then clears the mapping. + +Operator assignment is tracked historically via `operatorToSlot[parentIndex][operator]` checkpoints. + +## Restaking detection + +`isRestaked(subnetwork, operator)` and `isRestakedAt(subnetwork, operator, t, ...)` return `true` when the operator’s slot has any **shared ancestor**: + +- Walks up from the operator slot’s parent to the root. +- Returns `true` if any `slots[ancestor].isShared` is `1`. + +With the enforced depth policy, this means “restaked” is effectively “the operator’s network slot (depth 2) is under a shared group slot (depth 1)”. + +## Hints + +Some `*At(...)` view functions accept `bytes hints` to speed up checkpoint lookups. + +`stakeAt(...)` expects `hints` to be ABI-encoded as: + +```solidity +IUniversalDelegator.StakeHints({ + baseHints: /* hints forwarded to BaseDelegator opt-in checks */, + allocatedHints: /* hints forwarded into allocation lookups */ +}); +``` + +`UniversalDelegator` uses `allocatedHints` across multiple checkpoint traces. If you are not certain hints match the queried trace, pass empty bytes (`""`) to avoid reverts. + +## Caveats + +- `BaseDelegator.maxNetworkLimit` is currently not enforced by `UniversalDelegator` (`_setMaxNetworkLimit` is empty). + +## Minimal examples + +### Isolated groups (no restaking across depth 1) + +```solidity +// Create two depth-1 groups under root (root is not shared). +createSlot(0, false, type(uint256).max); // index: g1 +createSlot(0, false, type(uint256).max); // index: g2 +``` + +### Restaking between networks within a group (shared depth 1) + +```solidity +// Create a shared depth-1 group. +createSlot(0, true, type(uint256).max); // index: g + +// Create depth-2 networks under the shared group and assign subnetworks. +createSlot(g, false, 1_000e18); // index: n1 +createSlot(g, false, 1_000e18); // index: n2 +assignNetwork(n1, subnetwork1); +assignNetwork(n2, subnetwork2); + +// Create depth-3 operator slots under each network and assign operators. +createSlot(n1, false, 600e18); // index: o1 +assignOperator(o1, alice); +createSlot(n2, false, 600e18); // index: o2 +assignOperator(o2, bob); +``` diff --git a/src/contracts/delegator/NetworkRestakeDelegator.sol b/src/contracts/delegator/NetworkRestakeDelegator.sol index 58529a54..6d1fd875 100644 --- a/src/contracts/delegator/NetworkRestakeDelegator.sol +++ b/src/contracts/delegator/NetworkRestakeDelegator.sol @@ -130,8 +130,9 @@ contract NetworkRestakeDelegator is BaseDelegator, INetworkRestakeDelegator { revert AlreadySet(); } - _totalOperatorNetworkShares[subnetwork] - .push(Time.timestamp(), totalOperatorNetworkShares(subnetwork) - operatorNetworkShares_ + shares); + _totalOperatorNetworkShares[subnetwork].push( + Time.timestamp(), totalOperatorNetworkShares(subnetwork) - operatorNetworkShares_ + shares + ); _operatorNetworkShares[subnetwork][operator].push(Time.timestamp(), shares); emit SetOperatorNetworkShares(subnetwork, operator, shares); diff --git a/src/contracts/delegator/UniversalDelegator.sol b/src/contracts/delegator/UniversalDelegator.sol new file mode 100644 index 00000000..3254e733 --- /dev/null +++ b/src/contracts/delegator/UniversalDelegator.sol @@ -0,0 +1,380 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.25; + +import {BaseDelegator} from "./BaseDelegator.sol"; + +import {Checkpoints} from "../libraries/Checkpoints.sol"; +import {UniversalDelegatorIndex} from "../libraries/UniversalDelegatorIndex.sol"; + +import {IBaseDelegator} from "../../interfaces/delegator/IBaseDelegator.sol"; +import {IUniversalDelegator} from "../../interfaces/delegator/IUniversalDelegator.sol"; +import {IVault} from "../../interfaces/vault/IVault.sol"; + +import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; +import {MulticallUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/MulticallUpgradeable.sol"; + +contract UniversalDelegator is BaseDelegator, MulticallUpgradeable, IUniversalDelegator { + using UniversalDelegatorIndex for uint96; + using Checkpoints for Checkpoints.Trace256; + using Checkpoints for Checkpoints.Trace208; + using Math for uint256; + + struct Slot { + uint32[] children; + mapping(uint96 => uint32) childToLocalIndex; + Checkpoints.Trace256 size; + Checkpoints.Trace256 prevSum; + Checkpoints.Trace208 isShared; + Checkpoints.Trace256 pendingFreeCumulative; + } + + bytes32 public constant CURATOR_ROLE = keccak256("CURATOR_ROLE"); + uint256 MAX_DEPTH = 3; + + // @dev index is {32 bytes of child index at depth 1}{32 bytes - depth 2}{32 bytes - depth 3} + mapping(uint96 index => Slot slot) public slots; + mapping(bytes32 subnetwork => Checkpoints.Trace208) public networkToSlot; + mapping(uint96 parentIndex => mapping(address operator => Checkpoints.Trace208)) public operatorToSlot; + mapping(uint96 index => address operator) public operatorBySlot; + + constructor( + address networkRegistry, + address vaultFactory, + address operatorVaultOptInService, + address operatorNetworkOptInService, + address delegatorFactory, + uint64 entityType + ) + BaseDelegator( + networkRegistry, + vaultFactory, + operatorVaultOptInService, + operatorNetworkOptInService, + delegatorFactory, + entityType + ) + {} + + // @dev Returns the collateral balance of a given slot. + function getBalanceAt(uint96 index, uint48 timestamp, bytes memory hints) public view returns (uint256) { + if (index == 0) { + return IVault(vault).activeStakeAt(timestamp, hints); + } + return getAllocatedAt(index, timestamp, hints); + } + + function getBalance(uint96 index) public view returns (uint256) { + if (index == 0) { + return IVault(vault).activeStake(); + } + return getAllocated(index); + } + + // @dev Returns the available to allocate balance in the given slot. + function getAvailableAt(uint96 index, uint48 timestamp, bytes memory hints) public view returns (uint256) { + return getBalanceAt(index, timestamp, hints) + .saturatingSub( + slots[index].pendingFreeCumulative.upperLookupRecent(timestamp, hints) + - slots[index].pendingFreeCumulative + .upperLookupRecent( + uint48(uint256(timestamp).saturatingSub(IVault(vault).epochDuration())), hints + ) + ); + } + + function getAvailable(uint96 index) public view returns (uint256) { + return getBalance(index) + .saturatingSub( + slots[index].pendingFreeCumulative.latest() + - slots[index].pendingFreeCumulative + .upperLookupRecent(uint48(block.timestamp.saturatingSub(IVault(vault).epochDuration()))) + ); + } + + // @dev Returns the allocation of the given slot. + function getAllocatedAt(uint96 index, uint48 timestamp, bytes memory hints) public view returns (uint256) { + uint96 parentIndex = index.getParentIndex(); + Slot storage parent = slots[parentIndex]; + uint256 available = getAvailableAt(parentIndex, timestamp, hints); + if (parent.isShared.upperLookupRecent(timestamp, hints) == 0) { + available = available.saturatingSub(slots[index].prevSum.upperLookupRecent(timestamp, hints)); + } + return Math.min(available, slots[index].size.upperLookupRecent(timestamp, hints)); + } + + function getAllocated(uint96 index) public view returns (uint256) { + uint96 parentIndex = index.getParentIndex(); + Slot storage parent = slots[parentIndex]; + uint256 available = getAvailable(parentIndex); + if (parent.isShared.latest() == 0) { + available = available.saturatingSub(slots[index].prevSum.latest()); + } + return Math.min(available, slots[index].size.latest()); + } + + function getAllocatedAt(bytes32 subnetwork, address operator, uint48 timestamp, bytes memory hints) + public + view + returns (uint256) + { + uint96 index = slotByOperatorAt(slotByNetworkAt(subnetwork, timestamp, hints), operator, timestamp, hints); + return index > 0 ? getAllocatedAt(index, timestamp, hints) : 0; + } + + function getAllocated(bytes32 subnetwork, address operator) public view returns (uint256) { + uint96 index = slotByOperator(slotByNetwork(subnetwork), operator); + return index > 0 ? getAllocated(index) : 0; + } + + // @dev Returns the unallocated balance in the given slot (due to pendings or not fully allocated). + function getUnallocated(uint96 index) public view returns (uint256) { + return getAvailable(index).saturatingSub(_getChildrenSize(index)); + } + + function slotByNetworkAt(bytes32 subnetwork, uint48 timestamp, bytes memory hint) public view returns (uint96) { + return uint96(networkToSlot[subnetwork].upperLookupRecent(timestamp, hint)); + } + + function slotByNetwork(bytes32 subnetwork) public view returns (uint96) { + return uint96(networkToSlot[subnetwork].latest()); + } + + function slotByOperatorAt(uint96 parentIndex, address operator, uint48 timestamp, bytes memory hint) + public + view + returns (uint96) + { + return uint96(operatorToSlot[parentIndex][operator].upperLookupRecent(timestamp, hint)); + } + + function slotByOperator(uint96 parentIndex, address operator) public view returns (uint96) { + return uint96(operatorToSlot[parentIndex][operator].latest()); + } + + function isRestakedAt(bytes32 subnetwork, address operator, uint48 timestamp, bytes memory hints) + public + view + returns (bool) + { + uint96 index = slotByOperatorAt(slotByNetworkAt(subnetwork, timestamp, hints), operator, timestamp, hints); + if (index == 0) { + return false; + } + for (index = index.getParentIndex(); index > 0; index = index.getParentIndex()) { + if (slots[index].isShared.upperLookupRecent(timestamp, hints) > 0) { + return true; + } + } + return false; + } + + function isRestaked(bytes32 subnetwork, address operator) public view returns (bool) { + uint96 index = slotByOperator(slotByNetwork(subnetwork), operator); + if (index == 0) { + return false; + } + for (index = index.getParentIndex(); index > 0; index = index.getParentIndex()) { + if (slots[index].isShared.latest() > 0) { + return true; + } + } + return false; + } + + function createSlot(uint96 parentIndex, bool isShared, uint256 size) public onlyRole(CURATOR_ROLE) { + if (isShared && parentIndex.getDepth() > 0) { + revert WrongDepth(); + } + uint256 numChildren = slots[parentIndex].children.length; + uint32 childIndex = uint32(numChildren) + 1; + uint96 index = parentIndex.createIndex(childIndex); + Slot storage slot = slots[index]; + slot.prevSum.push(uint48(block.timestamp), _getChildrenSize(parentIndex)); + slot.isShared.push(uint48(block.timestamp), isShared ? 1 : 0); + slot.size.push(uint48(block.timestamp), size); + Slot storage parent = slots[parentIndex]; + parent.children.push(childIndex); + parent.childToLocalIndex[index] = uint32(numChildren); + + emit CreateSlot(index, size); + } + + function setIsShared(uint96 index, bool isShared) public onlyRole(CURATOR_ROLE) { + if (index.getDepth() != 1) { + revert WrongDepth(); + } + Slot storage slot = slots[index]; + if (slot.isShared.latest() == (isShared ? 1 : 0)) { + revert IsSharedNotChanged(); + } + if (getAllocated(index) > 0) { + revert SlotAllocated(); + } + slot.isShared.push(uint48(block.timestamp), isShared ? 1 : 0); + + emit SetIsShared(index, isShared); + } + + // @dev if size increase: just change the size if slot not fully allocated or last child, otherwise use unallocated funds + // @dev if size decrease: just change the size if slot not allocated, otherwise increase pending free + function setSize(uint96 index, uint256 size) public onlyRole(CURATOR_ROLE) { + Slot storage slot = slots[index]; + uint96 parentIndex = index.getParentIndex(); + Slot storage parent = slots[parentIndex]; + if (size > slot.size.latest()) { + if ( + parent.isShared.latest() == 0 && slot.prevSum.latest() + slot.size.latest() < getAvailable(parentIndex) + && parent.childToLocalIndex[index] < parent.children.length - 1 + && size - slot.size.latest() > getUnallocated(parentIndex) + ) { + revert NotEnoughAvailable(); + } + } else { + if (getAllocated(index) > size) { + parent.pendingFreeCumulative + .push(uint48(block.timestamp), getAllocated(index) - size + parent.pendingFreeCumulative.latest()); + } + } + slot.size.push(uint48(block.timestamp), size); + + _syncPrevSums(index); + + emit SetSize(index, size); + } + + function swapSlots(uint96 index1, uint96 index2) public onlyRole(CURATOR_ROLE) { + Slot storage slot1 = slots[index1]; + Slot storage slot2 = slots[index2]; + uint96 parentIndex = index1.getParentIndex(); + if (parentIndex != index2.getParentIndex()) { + revert NotSameParent(); + } + Slot storage parent = slots[parentIndex]; + (uint32 localIndex1, uint32 localIndex2) = (parent.childToLocalIndex[index1], parent.childToLocalIndex[index2]); + if (localIndex1 >= localIndex2) { + revert WrongOrder(); + } + uint256 available = getAvailable(parentIndex); + bool isAllocated = slot1.prevSum.latest() < available; + if (isAllocated != (slot2.prevSum.latest() < available)) { + revert NotSameAllocated(); + } + if (isAllocated && slot2.prevSum.latest() + slot2.size.latest() > available) { + revert PartiallyAllocated(); + } + (parent.children[localIndex1], parent.children[localIndex2]) = + (parent.children[localIndex2], parent.children[localIndex1]); + (parent.childToLocalIndex[index1], parent.childToLocalIndex[index2]) = (localIndex2, localIndex1); + + slot2.prevSum.push(uint48(block.timestamp), slot1.prevSum.latest()); + _syncPrevSums(index2); + + emit SwapSlots(index1, index2); + } + + function assignNetwork(uint96 index, bytes32 subnetwork) public onlyRole(CURATOR_ROLE) { + if (index.getDepth() != 2) { + revert WrongDepth(); + } + if (slotByNetwork(subnetwork) > 0) { + revert NetworkAlreadyAssigned(); + } + networkToSlot[subnetwork].push(uint48(block.timestamp), index); + + emit AssignNetwork(index, subnetwork); + } + + function unassignNetwork(bytes32 subnetwork) public onlyRole(CURATOR_ROLE) { + uint96 index = slotByNetwork(subnetwork); + if (index == 0) { + revert NetworkNotAssigned(); + } + if (getAllocated(index) > 0) { + revert SlotAllocated(); + } + networkToSlot[subnetwork].push(uint48(block.timestamp), 0); + + emit UnassignNetwork(subnetwork); + } + + function assignOperator(uint96 index, address operator) public onlyRole(CURATOR_ROLE) { + if (index.getDepth() != 3) { + revert WrongDepth(); + } + uint96 parentIndex = index.getParentIndex(); + if (slotByOperator(parentIndex, operator) != 0) { + revert OperatorAlreadyAssigned(); + } + operatorToSlot[parentIndex][operator].push(uint48(block.timestamp), index); + operatorBySlot[index] = operator; + + emit AssignOperator(index, operator); + } + + function unassignOperator(uint96 parentIndex, address operator) public onlyRole(CURATOR_ROLE) { + uint96 index = slotByOperator(parentIndex, operator); + if (index == 0) { + revert OperatorNotAssigned(); + } + if (getAllocated(index) > 0) { + revert SlotAllocated(); + } + operatorToSlot[parentIndex][operator].push(uint48(block.timestamp), 0); + delete operatorBySlot[index]; + + emit UnassignOperator(index, operator); + } + + function _getChildrenSize(uint96 index) internal view returns (uint256) { + uint256 numChildren = slots[index].children.length; + if (numChildren == 0) { + return 0; + } + Slot storage child = slots[index.createIndex(slots[index].children[numChildren - 1])]; + return child.prevSum.latest() + child.size.latest(); + } + + function _syncPrevSums(uint96 startIndex) internal { + Slot storage slot = slots[startIndex]; + uint96 parentIndex = startIndex.getParentIndex(); + Slot storage parent = slots[parentIndex]; + uint256 prevSum = slot.prevSum.latest() + slot.size.latest(); + uint256 numChildren = parent.children.length; + for (uint32 i = parent.childToLocalIndex[startIndex] + 1; i < numChildren; ++i) { + Slot storage child = slots[parentIndex.createIndex(parent.children[i])]; + child.prevSum.push(uint48(block.timestamp), prevSum); + prevSum += child.size.latest(); + } + } + + function _stakeAt(bytes32 subnetwork, address operator, uint48 timestamp, bytes memory hints) + internal + view + override + returns (uint256, bytes memory) + { + StakeHints memory stakesHints; + if (hints.length > 0) { + stakesHints = abi.decode(hints, (StakeHints)); + } + return (getAllocatedAt(subnetwork, operator, timestamp, stakesHints.allocatedHints), stakesHints.baseHints); + } + + function _stake(bytes32 subnetwork, address operator) internal view override returns (uint256) { + return getAllocated(subnetwork, operator); + } + + function _setMaxNetworkLimit(bytes32 subnetwork, uint256 amount) internal override {} + + function __initialize(address, bytes memory data) internal override returns (IBaseDelegator.BaseParams memory) { + InitParams memory params = abi.decode(data, (InitParams)); + + if (params.baseParams.defaultAdminRoleHolder == address(0) && params.curatorRoleHolder == address(0)) { + revert MissingRoleHolders(); + } + + _grantRole(CURATOR_ROLE, params.curatorRoleHolder); + + return params.baseParams; + } +} diff --git a/src/contracts/libraries/UniversalDelegatorIndex.sol b/src/contracts/libraries/UniversalDelegatorIndex.sol new file mode 100644 index 00000000..a0570423 --- /dev/null +++ b/src/contracts/libraries/UniversalDelegatorIndex.sol @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +library UniversalDelegatorIndex { + error NotParentIndex(); + error ZeroIndex(); + + function createIndex(uint96 parentIndex, uint32 localIndex) internal pure returns (uint96) { + if (parentIndex == 0) { + return uint96(localIndex) << 64; + } + if (parentIndex << 32 == 0) { + return parentIndex | uint96(localIndex) << 32; + } + if (parentIndex << 64 == 0) { + return parentIndex | uint96(localIndex); + } + revert NotParentIndex(); + } + + function getParentIndex(uint96 index) internal pure returns (uint96) { + if (index == 0) { + revert ZeroIndex(); + } + if (index << 32 == 0) { + return 0; + } + if (index << 64 == 0) { + return index & 0xFFFFFFFF0000000000000000; + } + return index & 0xFFFFFFFFFFFFFFFF00000000; + } + + function getChildIndex(uint96 index) internal pure returns (uint32) { + if (index == 0) { + revert ZeroIndex(); + } + if (index << 32 == 0) { + return uint32(index >> 64); + } + if (index << 64 == 0) { + return uint32(index >> 32); + } + return uint32(index); + } + + function getDepth(uint96 index) internal pure returns (uint256) { + if (index == 0) { + return 0; + } + if (index << 32 == 0) { + return 1; + } + if (index << 64 == 0) { + return 2; + } + return 3; + } +} diff --git a/src/contracts/slasher/VetoSlasher.sol b/src/contracts/slasher/VetoSlasher.sol index e90ce07d..1f18bb91 100644 --- a/src/contracts/slasher/VetoSlasher.sol +++ b/src/contracts/slasher/VetoSlasher.sol @@ -252,8 +252,7 @@ contract VetoSlasher is BaseSlasher, IVetoSlasher { } if (resolver_ != address(uint160(_resolver[subnetwork].latest()))) { - _resolver[subnetwork] - .push( + _resolver[subnetwork].push( (IVault(vault_).currentEpochStart() + resolverSetEpochsDelay * IVault(vault_).epochDuration()) .toUint48(), uint160(resolver_) diff --git a/src/interfaces/delegator/IBaseDelegator.sol b/src/interfaces/delegator/IBaseDelegator.sol index 91b129ac..0340f212 100644 --- a/src/interfaces/delegator/IBaseDelegator.sol +++ b/src/interfaces/delegator/IBaseDelegator.sol @@ -174,11 +174,6 @@ interface IBaseDelegator is IEntity { * @param data some additional data * @dev Only the vault's slasher can call this function. */ - function onSlash( - bytes32 subnetwork, - address operator, - uint256 amount, - uint48 captureTimestamp, - bytes calldata data - ) external; + function onSlash(bytes32 subnetwork, address operator, uint256 amount, uint48 captureTimestamp, bytes calldata data) + external; } diff --git a/src/interfaces/delegator/IDelegatorHook.sol b/src/interfaces/delegator/IDelegatorHook.sol index d2241fca..61333955 100644 --- a/src/interfaces/delegator/IDelegatorHook.sol +++ b/src/interfaces/delegator/IDelegatorHook.sol @@ -10,11 +10,6 @@ interface IDelegatorHook { * @param captureTimestamp time point when the stake was captured * @param data some additional data */ - function onSlash( - bytes32 subnetwork, - address operator, - uint256 amount, - uint48 captureTimestamp, - bytes calldata data - ) external; + function onSlash(bytes32 subnetwork, address operator, uint256 amount, uint48 captureTimestamp, bytes calldata data) + external; } diff --git a/src/interfaces/delegator/IUniversalDelegator.sol b/src/interfaces/delegator/IUniversalDelegator.sol new file mode 100644 index 00000000..aa54805a --- /dev/null +++ b/src/interfaces/delegator/IUniversalDelegator.sol @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {IBaseDelegator} from "./IBaseDelegator.sol"; + +interface IUniversalDelegator is IBaseDelegator { + error NotEnoughAvailable(); + error NotSameParent(); + error WrongOrder(); + error NotSameAllocated(); + error PartiallyAllocated(); + error NetworkAlreadyAssigned(); + error NetworkNotAssigned(); + error OperatorAlreadyAssigned(); + error OperatorNotAssigned(); + error SlotAllocated(); + error MissingRoleHolders(); + error IsSharedNotChanged(); + error WrongDepth(); + + struct InitParams { + BaseParams baseParams; + address curatorRoleHolder; + } + + struct StakeHints { + bytes baseHints; + bytes allocatedHints; + } + + event CreateSlot(uint96 indexed index, uint256 size); + + event SetIsShared(uint96 indexed index, bool isShared); + + event SetSize(uint96 indexed index, uint256 size); + + event SwapSlots(uint96 indexed index1, uint96 indexed index2); + + event AssignNetwork(uint96 indexed index, bytes32 indexed subnetwork); + + event UnassignNetwork(bytes32 indexed subnetwork); + + event AssignOperator(uint96 indexed index, address indexed operator); + + event UnassignOperator(uint96 indexed index, address indexed operator); +} diff --git a/test/delegator/UniversalDelegator.t.py b/test/delegator/UniversalDelegator.t.py new file mode 100644 index 00000000..ae3a20bc --- /dev/null +++ b/test/delegator/UniversalDelegator.t.py @@ -0,0 +1,97 @@ +import unittest + +import sim + + +class CheckpointTests(unittest.TestCase): + def tearDown(self): + sim.CURRENT_TIME = 0 + + def test_checkpoint_tracks_history_and_defaults(self): + checkpoint = sim.Checkpoint[int](default=0) + self.assertEqual(checkpoint.latest(), 0) + + checkpoint.push(5, 10) + checkpoint.push(7, 20) + + self.assertEqual(checkpoint.lower_bound(4), 0) + self.assertEqual(checkpoint.lower_bound(5), 10) + self.assertEqual(checkpoint.lower_bound(6), 10) + self.assertEqual(checkpoint.lower_bound(7), 20) + self.assertEqual(checkpoint.lower_bound(9), 20) + self.assertEqual(checkpoint.latest(), 20) + + +class DelegatorTests(unittest.TestCase): + def setUp(self): + sim.CURRENT_TIME = 0 + self.delegator = sim.Delegator(delay=3) + + def tearDown(self): + sim.CURRENT_TIME = 0 + + def test_slot_allocation_partial_fill(self): + self.delegator.on_deposit(100) + self.delegator.slot_add(30, "alice") + self.delegator.slot_add(500, "bob") + + self.assertEqual(self.delegator.get_current_unallocated(), 0) + self.assertEqual(self.delegator.get_slot_allocation_by_owner(0, "alice"), 30) + self.assertEqual(self.delegator.get_slot_allocation_by_owner(0, "bob"), 70) + self.assertEqual(self.delegator.get_slot_order(1), 1) + + def test_slot_allocation_partial_fill_2(self): + self.delegator.on_deposit(100) + self.delegator.slot_add(500, "alice") + self.delegator.slot_add(30, "bob") + + self.assertEqual(self.delegator.get_current_unallocated(), 0) + self.assertEqual(self.delegator.get_slot_allocation_by_owner(0, "alice"), 100) + self.assertEqual(self.delegator.get_slot_allocation_by_owner(0, "bob"), 0) + self.assertEqual(self.delegator.get_slot_order(1), 1) + + def test_slot_allocation_respects_order_and_limits(self): + self.delegator.on_deposit(100) + self.delegator.slot_add(30, "alice") + self.delegator.slot_add(50, "bob") + + self.assertEqual(self.delegator.get_current_unallocated(), 20) + self.assertEqual(self.delegator.get_slot_allocation_by_owner(0, "alice"), 30) + self.assertEqual(self.delegator.get_slot_allocation_by_owner(0, "bob"), 50) + self.assertEqual(self.delegator.get_slot_order(1), 1) + + def test_increase_limit_consumes_unallocated_and_updates_prev_sums(self): + self.delegator.on_deposit(100) + self.delegator.slot_add(30, "alice") + self.delegator.slot_add(50, "bob") + + sim.CURRENT_TIME = 1 + self.assertTrue(self.delegator.slot_increase_limit(0, 15)) + self.assertEqual(self.delegator.slots[0].get_limit(1), 45) + self.assertEqual(self.delegator.slots[1].get_prev_sum(1), 45) + self.assertEqual(self.delegator.get_slot_allocation_by_owner(1, "alice"), 45) + self.assertEqual(self.delegator.get_current_unallocated(), 5) + + def test_decrease_limit_schedules_pending_free_until_delay_expires(self): + self.delegator.on_deposit(100) + self.delegator.slot_add(60, "alice") + self.delegator.slot_add(30, "bob") + + sim.CURRENT_TIME = 1 + self.assertTrue(self.delegator.slot_decrease_limit(0, 20)) + self.assertEqual(self.delegator.slots[0].get_limit(1), 40) + self.assertEqual(self.delegator.slots[1].get_prev_sum(1), 40) + + sim.CURRENT_TIME = 2 + self.assertEqual(self.delegator.get_available(2), 80) + self.assertEqual(self.delegator.get_current_unallocated(), 10) + + sim.CURRENT_TIME = 4 + self.assertEqual(self.delegator.get_available(4), 100) + self.assertEqual(self.delegator.get_slot_allocation_by_owner(4, "alice"), 40) + self.assertEqual(self.delegator.get_slot_allocation_by_owner(4, "bob"), 30) + self.assertEqual(self.delegator.get_current_unallocated(), 30) + + +if __name__ == "__main__": + unittest.main() \ No newline at end of file diff --git a/test/delegator/UniversalDelegator.t.sol b/test/delegator/UniversalDelegator.t.sol new file mode 100644 index 00000000..e3c1c4bc --- /dev/null +++ b/test/delegator/UniversalDelegator.t.sol @@ -0,0 +1,680 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.25; + +import {Test} from "forge-std/Test.sol"; + +import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol"; + +import {VaultFactory} from "../../src/contracts/VaultFactory.sol"; +import {DelegatorFactory} from "../../src/contracts/DelegatorFactory.sol"; +import {SlasherFactory} from "../../src/contracts/SlasherFactory.sol"; +import {VaultConfigurator} from "../../src/contracts/VaultConfigurator.sol"; + +import {Vault} from "../../src/contracts/vault/Vault.sol"; +import {UniversalDelegator} from "../../src/contracts/delegator/UniversalDelegator.sol"; + +import {UniversalDelegatorIndex} from "../../src/contracts/libraries/UniversalDelegatorIndex.sol"; + +import {IBaseDelegator} from "../../src/interfaces/delegator/IBaseDelegator.sol"; +import {IUniversalDelegator} from "../../src/interfaces/delegator/IUniversalDelegator.sol"; +import {IVault} from "../../src/interfaces/vault/IVault.sol"; +import {IVaultConfigurator} from "../../src/interfaces/IVaultConfigurator.sol"; + +import {Token} from "../mocks/Token.sol"; + +contract UniversalDelegatorTest is Test { + using UniversalDelegatorIndex for uint96; + + uint48 internal constant EPOCH_DURATION = 3; + + address internal owner; + address internal alice; + address internal bob; + + VaultFactory internal vaultFactory; + DelegatorFactory internal delegatorFactory; + SlasherFactory internal slasherFactory; + VaultConfigurator internal vaultConfigurator; + + Token internal collateral; + Vault internal vault; + UniversalDelegator internal delegator; + + function setUp() public { + vm.warp(0); + + owner = address(this); + alice = makeAddr("alice"); + bob = makeAddr("bob"); + + vaultFactory = new VaultFactory(owner); + delegatorFactory = new DelegatorFactory(owner); + slasherFactory = new SlasherFactory(owner); + + address vaultImpl = + address(new Vault(address(delegatorFactory), address(slasherFactory), address(vaultFactory))); + vaultFactory.whitelist(vaultImpl); + + address delegatorImpl = address( + new UniversalDelegator( + address(0x1111), + address(vaultFactory), + address(0x2222), + address(0x3333), + address(delegatorFactory), + delegatorFactory.totalTypes() + ) + ); + delegatorFactory.whitelist(delegatorImpl); + + collateral = new Token("Token"); + vaultConfigurator = + new VaultConfigurator(address(vaultFactory), address(delegatorFactory), address(slasherFactory)); + + (address vault_, address delegator_,) = vaultConfigurator.create( + IVaultConfigurator.InitParams({ + version: vaultFactory.lastVersion(), + owner: owner, + vaultParams: abi.encode( + IVault.InitParams({ + collateral: address(collateral), + burner: address(0xdEaD), + epochDuration: EPOCH_DURATION, + depositWhitelist: false, + isDepositLimit: false, + depositLimit: 0, + defaultAdminRoleHolder: owner, + depositWhitelistSetRoleHolder: address(0), + depositorWhitelistRoleHolder: address(0), + isDepositLimitSetRoleHolder: address(0), + depositLimitSetRoleHolder: address(0) + }) + ), + delegatorIndex: 0, + delegatorParams: abi.encode( + IUniversalDelegator.InitParams({ + baseParams: IBaseDelegator.BaseParams({ + defaultAdminRoleHolder: address(0), hook: address(0), hookSetRoleHolder: address(0) + }), + curatorRoleHolder: owner + }) + ), + withSlasher: false, + slasherIndex: 0, + slasherParams: "" + }) + ); + + vault = Vault(vault_); + delegator = UniversalDelegator(delegator_); + } + + function test_checkpointTracksHistory_andDefaults() public { + delegator.createSlot(0, false, 30); + uint96 slot1 = uint96(0).createIndex(uint32(1)); + + assertEq(delegator.getAllocatedAt(slot1, 0, ""), 0); + + vm.warp(5); + _deposit(alice, 100); + assertEq(delegator.getAllocatedAt(slot1, 5, ""), 30); + + vm.warp(7); + delegator.setSize(slot1, 20); + assertEq(delegator.getAllocatedAt(slot1, 7, ""), 20); + assertEq(delegator.getAllocatedAt(slot1, 9, ""), 20); + } + + function test_slotAllocation_partialFill() public { + _deposit(alice, 100); + + delegator.createSlot(0, false, 30); + delegator.createSlot(0, false, 500); + + uint96 slot1 = uint96(0).createIndex(uint32(1)); + uint96 slot2 = uint96(0).createIndex(uint32(2)); + + assertEq(delegator.getUnallocated(0), 0); + assertEq(delegator.getAllocated(slot1), 30); + assertEq(delegator.getAllocated(slot2), 70); + } + + function test_slotAllocation_partialFill_2() public { + _deposit(alice, 100); + + delegator.createSlot(0, false, 500); + delegator.createSlot(0, false, 30); + + uint96 slot1 = uint96(0).createIndex(uint32(1)); + uint96 slot2 = uint96(0).createIndex(uint32(2)); + + assertEq(delegator.getUnallocated(0), 0); + assertEq(delegator.getAllocated(slot1), 100); + assertEq(delegator.getAllocated(slot2), 0); + } + + function test_slotAllocation_respectsOrderAndLimits() public { + _deposit(alice, 100); + + delegator.createSlot(0, false, 30); + delegator.createSlot(0, false, 50); + + uint96 slot1 = uint96(0).createIndex(uint32(1)); + uint96 slot2 = uint96(0).createIndex(uint32(2)); + + assertEq(delegator.getUnallocated(0), 20); + assertEq(delegator.getAllocated(slot1), 30); + assertEq(delegator.getAllocated(slot2), 50); + } + + function test_increaseLimit_consumesUnallocated_andUpdatesPrevSums() public { + _deposit(alice, 100); + + delegator.createSlot(0, false, 30); + delegator.createSlot(0, false, 50); + + uint96 slot1 = uint96(0).createIndex(uint32(1)); + uint96 slot2 = uint96(0).createIndex(uint32(2)); + + vm.warp(1); + delegator.setSize(slot1, 45); + + assertEq(delegator.getAllocatedAt(slot1, 1, ""), 45); + assertEq(delegator.getAllocatedAt(slot2, 1, ""), 50); + assertEq(delegator.getUnallocated(0), 5); + } + + function test_increaseLimit_revertsWhenFullyAllocatedNonLast_withoutUnallocated() public { + _deposit(alice, 100); + + delegator.createSlot(0, false, 60); + delegator.createSlot(0, false, 60); + + uint96 slot1 = uint96(0).createIndex(uint32(1)); + + vm.expectRevert(IUniversalDelegator.NotEnoughAvailable.selector); + delegator.setSize(slot1, 80); + } + + function test_increaseLimit_allowsWhenNotFullyAllocated_evenIfNotLastChild() public { + _deposit(alice, 100); + + delegator.createSlot(0, false, 60); + delegator.createSlot(0, false, 60); + delegator.createSlot(0, false, 60); + + uint96 slot2 = uint96(0).createIndex(uint32(2)); + uint96 slot3 = uint96(0).createIndex(uint32(3)); + + delegator.setSize(slot2, 80); + + assertEq(delegator.getAllocated(slot2), 40); + assertEq(delegator.getAllocated(slot3), 0); + assertEq(delegator.getUnallocated(0), 0); + } + + function test_increaseLimit_allowsLastChild_withoutUnallocated() public { + _deposit(alice, 100); + + delegator.createSlot(0, false, 30); + delegator.createSlot(0, false, 30); + + uint96 slot1 = uint96(0).createIndex(uint32(1)); + uint96 slot2 = uint96(0).createIndex(uint32(2)); + + delegator.setSize(slot2, 90); + + assertEq(delegator.getAllocated(slot1), 30); + assertEq(delegator.getAllocated(slot2), 70); + assertEq(delegator.getUnallocated(0), 0); + } + + function test_decreaseLimit_schedulesPendingFree_untilDelayExpires() public { + _deposit(alice, 100); + + delegator.createSlot(0, false, 60); + delegator.createSlot(0, false, 30); + + uint96 slot1 = uint96(0).createIndex(uint32(1)); + uint96 slot2 = uint96(0).createIndex(uint32(2)); + + vm.warp(1); + delegator.setSize(slot1, 40); + + vm.warp(2); + assertEq(delegator.getAvailable(0), 80); + assertEq(delegator.getAllocated(slot1), 40); + assertEq(delegator.getAllocated(slot2), 30); + assertEq(delegator.getUnallocated(0), 10); + + vm.warp(4); + assertEq(delegator.getAvailable(0), 100); + assertEq(delegator.getAllocated(slot1), 40); + assertEq(delegator.getAllocated(slot2), 30); + assertEq(delegator.getUnallocated(0), 30); + } + + function test_pendingFree_respectsAllocationWhenResizingChildren() public { + _deposit(alice, 555); + + delegator.createSlot(0, false, 555); + uint96 group = uint96(0).createIndex(uint32(1)); + + delegator.createSlot(group, false, 444); + uint96 networkSlot = group.createIndex(uint32(1)); + + delegator.createSlot(networkSlot, false, 444); + uint96 operatorSlot = networkSlot.createIndex(uint32(1)); + + assertEq(delegator.getAllocated(group), 555); + assertEq(delegator.getAllocated(networkSlot), 444); + assertEq(delegator.getAllocated(operatorSlot), 444); + + vm.warp(1); + delegator.setSize(networkSlot, 222); + + assertEq(delegator.getAvailable(group), 333); + assertEq(delegator.getAllocated(networkSlot), 222); + assertEq(delegator.getAllocated(operatorSlot), 222); + + vm.warp(2); + delegator.setSize(operatorSlot, 222); + + assertEq(delegator.getAvailable(networkSlot), 222); + assertEq(delegator.getAllocated(operatorSlot), 222); + + uint256 groupPending = delegator.getBalance(group) - delegator.getAvailable(group); + uint256 networkPending = delegator.getBalance(networkSlot) - delegator.getAvailable(networkSlot); + uint256 operatorPending = delegator.getBalance(operatorSlot) - delegator.getAvailable(operatorSlot); + + assertEq(groupPending, 222); + assertEq(networkPending, 0); + assertEq(operatorPending, 0); + } + + function test_pendingFree_accumulatesOnRepeatedOperatorDecrease() public { + _deposit(alice, 555); + + delegator.createSlot(0, false, 555); + uint96 group = uint96(0).createIndex(uint32(1)); + + delegator.createSlot(group, false, 444); + uint96 networkSlot = group.createIndex(uint32(1)); + + delegator.createSlot(networkSlot, false, 444); + uint96 operatorSlot = networkSlot.createIndex(uint32(1)); + + vm.warp(1); + delegator.setSize(operatorSlot, 222); + + uint256 pendingAfterFirst = delegator.getBalance(networkSlot) - delegator.getAvailable(networkSlot); + assertEq(pendingAfterFirst, 222); + assertEq(delegator.getAllocated(operatorSlot), 222); + + vm.warp(2); + delegator.setSize(operatorSlot, 0); + + uint256 pendingAfterSecond = delegator.getBalance(networkSlot) - delegator.getAvailable(networkSlot); + assertEq(pendingAfterSecond, 444); + assertEq(delegator.getAllocated(networkSlot), 444); + assertEq(delegator.getAllocated(operatorSlot), 0); + + uint256 groupPending = delegator.getBalance(group) - delegator.getAvailable(group); + assertEq(groupPending, 0); + } + + function test_sharedGroup_allowsNetworkRestaking_betweenDepth2Siblings() public { + _deposit(alice, 100); + + delegator.createSlot(0, true, 100); + uint96 group = uint96(0).createIndex(uint32(1)); + + delegator.createSlot(group, false, 80); + delegator.createSlot(group, false, 80); + uint96 net1 = group.createIndex(uint32(1)); + uint96 net2 = group.createIndex(uint32(2)); + + assertEq(delegator.getAllocated(group), 100); + assertEq(delegator.getAllocated(net1), 80); + assertEq(delegator.getAllocated(net2), 80); + } + + function test_depth3Operators_areIsolatedWithinNetwork() public { + _deposit(alice, 100); + + delegator.createSlot(0, true, 100); + uint96 group = uint96(0).createIndex(uint32(1)); + + delegator.createSlot(group, false, 80); + uint96 net1 = group.createIndex(uint32(1)); + + delegator.createSlot(net1, false, 50); + delegator.createSlot(net1, false, 50); + uint96 op1 = net1.createIndex(uint32(1)); + uint96 op2 = net1.createIndex(uint32(2)); + + assertEq(delegator.getAllocated(net1), 80); + assertEq(delegator.getAllocated(op1), 50); + assertEq(delegator.getAllocated(op2), 30); + } + + function test_isRestaked_trueWhenGroupIsShared() public { + bytes32 subnetwork = bytes32(uint256(1)); + + _deposit(alice, 100); + + delegator.createSlot(0, true, 100); + uint96 group = uint96(0).createIndex(uint32(1)); + + delegator.createSlot(group, false, 100); + uint96 networkSlot = group.createIndex(uint32(1)); + delegator.assignNetwork(networkSlot, subnetwork); + + delegator.createSlot(networkSlot, false, 100); + uint96 operatorSlot = networkSlot.createIndex(uint32(1)); + delegator.assignOperator(operatorSlot, alice); + + assertTrue(delegator.isRestaked(subnetwork, alice)); + assertTrue(delegator.isRestakedAt(subnetwork, alice, uint48(block.timestamp), "")); + } + + function test_isRestaked_falseWhenGroupNotShared() public { + bytes32 subnetwork = bytes32(uint256(1)); + + _deposit(alice, 100); + + delegator.createSlot(0, false, 100); + uint96 group = uint96(0).createIndex(uint32(1)); + + delegator.createSlot(group, false, 100); + uint96 networkSlot = group.createIndex(uint32(1)); + delegator.assignNetwork(networkSlot, subnetwork); + + delegator.createSlot(networkSlot, false, 100); + uint96 operatorSlot = networkSlot.createIndex(uint32(1)); + delegator.assignOperator(operatorSlot, alice); + + assertFalse(delegator.isRestaked(subnetwork, alice)); + assertFalse(delegator.isRestakedAt(subnetwork, alice, uint48(block.timestamp), "")); + } + + function test_onlyCuratorRole_enforced() public { + vm.startPrank(bob); + + vm.expectRevert( + abi.encodeWithSelector( + IAccessControl.AccessControlUnauthorizedAccount.selector, bob, delegator.CURATOR_ROLE() + ) + ); + delegator.createSlot(0, false, 1); + + vm.expectRevert( + abi.encodeWithSelector( + IAccessControl.AccessControlUnauthorizedAccount.selector, bob, delegator.CURATOR_ROLE() + ) + ); + delegator.setIsShared(uint96(0).createIndex(uint32(1)), true); + + vm.expectRevert( + abi.encodeWithSelector( + IAccessControl.AccessControlUnauthorizedAccount.selector, bob, delegator.CURATOR_ROLE() + ) + ); + delegator.setSize(uint96(0).createIndex(uint32(1)), 1); + + vm.expectRevert( + abi.encodeWithSelector( + IAccessControl.AccessControlUnauthorizedAccount.selector, bob, delegator.CURATOR_ROLE() + ) + ); + delegator.swapSlots(uint96(0).createIndex(uint32(1)), uint96(0).createIndex(uint32(2))); + + vm.expectRevert( + abi.encodeWithSelector( + IAccessControl.AccessControlUnauthorizedAccount.selector, bob, delegator.CURATOR_ROLE() + ) + ); + delegator.assignNetwork(uint96(0).createIndex(uint32(1)), bytes32(uint256(1))); + + vm.expectRevert( + abi.encodeWithSelector( + IAccessControl.AccessControlUnauthorizedAccount.selector, bob, delegator.CURATOR_ROLE() + ) + ); + delegator.unassignNetwork(bytes32(uint256(1))); + + vm.expectRevert( + abi.encodeWithSelector( + IAccessControl.AccessControlUnauthorizedAccount.selector, bob, delegator.CURATOR_ROLE() + ) + ); + delegator.assignOperator(uint96(0).createIndex(uint32(1)), bob); + + vm.expectRevert( + abi.encodeWithSelector( + IAccessControl.AccessControlUnauthorizedAccount.selector, bob, delegator.CURATOR_ROLE() + ) + ); + delegator.unassignOperator(uint96(0).createIndex(uint32(1)), bob); + + vm.stopPrank(); + } + + function test_depthGuards_enforced() public { + delegator.createSlot(0, false, 100); + uint96 group = uint96(0).createIndex(uint32(1)); + + delegator.createSlot(group, false, 100); + uint96 networkSlot = group.createIndex(uint32(1)); + + delegator.createSlot(networkSlot, false, 100); + uint96 operatorSlot = networkSlot.createIndex(uint32(1)); + + vm.expectRevert(IUniversalDelegator.WrongDepth.selector); + delegator.setIsShared(0, true); + + vm.expectRevert(IUniversalDelegator.WrongDepth.selector); + delegator.setIsShared(networkSlot, true); + + vm.expectRevert(IUniversalDelegator.WrongDepth.selector); + delegator.setIsShared(operatorSlot, true); + + vm.expectRevert(IUniversalDelegator.WrongDepth.selector); + delegator.assignNetwork(group, bytes32(uint256(1))); + + vm.expectRevert(IUniversalDelegator.WrongDepth.selector); + delegator.assignOperator(networkSlot, alice); + + vm.expectRevert(IUniversalDelegator.WrongDepth.selector); + delegator.createSlot(group, true, 1); + } + + function test_networkAssignment_duplicateAndUnassignChecks() public { + bytes32 subnetwork = bytes32(uint256(1)); + + vm.expectRevert(IUniversalDelegator.NetworkNotAssigned.selector); + delegator.unassignNetwork(subnetwork); + + _deposit(alice, 100); + + delegator.createSlot(0, false, 100); + uint96 group = uint96(0).createIndex(uint32(1)); + + delegator.createSlot(group, false, 100); + delegator.createSlot(group, false, 100); + uint96 net1 = group.createIndex(uint32(1)); + uint96 net2 = group.createIndex(uint32(2)); + + delegator.assignNetwork(net1, subnetwork); + + vm.expectRevert(IUniversalDelegator.NetworkAlreadyAssigned.selector); + delegator.assignNetwork(net2, subnetwork); + + vm.expectRevert(IUniversalDelegator.SlotAllocated.selector); + delegator.unassignNetwork(subnetwork); + + _withdraw(alice, 100); + delegator.unassignNetwork(subnetwork); + assertEq(delegator.slotByNetwork(subnetwork), 0); + } + + function test_operatorAssignment_duplicateAndUnassignChecks() public { + _deposit(alice, 100); + + delegator.createSlot(0, false, 100); + uint96 group = uint96(0).createIndex(uint32(1)); + + delegator.createSlot(group, false, 100); + uint96 networkSlot = group.createIndex(uint32(1)); + + delegator.createSlot(networkSlot, false, 60); + delegator.createSlot(networkSlot, false, 60); + uint96 operatorSlot1 = networkSlot.createIndex(uint32(1)); + uint96 operatorSlot2 = networkSlot.createIndex(uint32(2)); + + vm.expectRevert(IUniversalDelegator.OperatorNotAssigned.selector); + delegator.unassignOperator(networkSlot, alice); + + delegator.assignOperator(operatorSlot1, alice); + + vm.expectRevert(IUniversalDelegator.OperatorAlreadyAssigned.selector); + delegator.assignOperator(operatorSlot2, alice); + + vm.expectRevert(IUniversalDelegator.SlotAllocated.selector); + delegator.unassignOperator(networkSlot, alice); + + _withdraw(alice, 100); + delegator.unassignOperator(networkSlot, alice); + assertEq(delegator.slotByOperator(networkSlot, alice), 0); + } + + function test_setIsShared_revertsWhenAllocated() public { + _deposit(alice, 1); + + delegator.createSlot(0, false, 1); + uint96 group = uint96(0).createIndex(uint32(1)); + + vm.expectRevert(IUniversalDelegator.SlotAllocated.selector); + delegator.setIsShared(group, true); + } + + function test_setIsShared_togglesNetworkRestaking() public { + delegator.createSlot(0, false, 100); + uint96 group = uint96(0).createIndex(uint32(1)); + + delegator.createSlot(group, false, 80); + delegator.createSlot(group, false, 80); + uint96 net1 = group.createIndex(uint32(1)); + uint96 net2 = group.createIndex(uint32(2)); + + _deposit(alice, 100); + assertEq(delegator.getAllocated(net1), 80); + assertEq(delegator.getAllocated(net2), 20); + + _withdraw(alice, 100); + + delegator.setIsShared(group, true); + + _deposit(alice, 100); + assertEq(delegator.getAllocated(net1), 80); + assertEq(delegator.getAllocated(net2), 80); + } + + function test_swapSlots_changesAllocationAfterStakeDecrease() public { + _deposit(alice, 100); + + delegator.createSlot(0, false, 30); + delegator.createSlot(0, false, 50); + + uint96 slot1 = uint96(0).createIndex(uint32(1)); + uint96 slot2 = uint96(0).createIndex(uint32(2)); + + vm.warp(1); + delegator.swapSlots(slot1, slot2); + + vm.warp(2); + _withdraw(alice, 60); + + assertEq(delegator.getAllocated(slot2), 40); + assertEq(delegator.getAllocated(slot1), 0); + } + + function test_swapSlots_revertsWrongOrder() public { + _deposit(alice, 100); + + delegator.createSlot(0, false, 10); + delegator.createSlot(0, false, 10); + uint96 slot1 = uint96(0).createIndex(uint32(1)); + uint96 slot2 = uint96(0).createIndex(uint32(2)); + + vm.expectRevert(IUniversalDelegator.WrongOrder.selector); + delegator.swapSlots(slot2, slot1); + } + + function test_swapSlots_revertsNotSameParent() public { + _deposit(alice, 100); + + delegator.createSlot(0, false, 10); + uint96 rootSlot = uint96(0).createIndex(uint32(1)); + + delegator.createSlot(0, false, 10); + uint96 group = uint96(0).createIndex(uint32(2)); + delegator.createSlot(group, false, 10); + uint96 networkSlot = group.createIndex(uint32(1)); + + vm.expectRevert(IUniversalDelegator.NotSameParent.selector); + delegator.swapSlots(rootSlot, networkSlot); + } + + function test_swapSlots_revertsNotSameAllocated() public { + _deposit(alice, 3); + + delegator.createSlot(0, false, 5); + delegator.createSlot(0, false, 5); + uint96 slot1 = uint96(0).createIndex(uint32(1)); + uint96 slot2 = uint96(0).createIndex(uint32(2)); + + vm.expectRevert(IUniversalDelegator.NotSameAllocated.selector); + delegator.swapSlots(slot1, slot2); + } + + function test_swapSlots_revertsPartiallyAllocated() public { + _deposit(alice, 70); + + delegator.createSlot(0, false, 50); + delegator.createSlot(0, false, 50); + uint96 slot1 = uint96(0).createIndex(uint32(1)); + uint96 slot2 = uint96(0).createIndex(uint32(2)); + + vm.expectRevert(IUniversalDelegator.PartiallyAllocated.selector); + delegator.swapSlots(slot1, slot2); + } + + function test_getAvailableAt_doesNotUnderflowForSmallTimestamps() public { + _deposit(alice, 100); + + delegator.createSlot(0, false, 60); + uint96 slot1 = uint96(0).createIndex(uint32(1)); + + vm.warp(1); + delegator.setSize(slot1, 40); + + assertEq(delegator.getAvailableAt(0, 2, ""), 80); + assertEq(delegator.getAvailableAt(0, 4, ""), 100); + } + + function _deposit(address user, uint256 amount) internal { + collateral.transfer(user, amount); + + vm.startPrank(user); + collateral.approve(address(vault), amount); + vault.deposit(user, amount); + vm.stopPrank(); + } + + function _withdraw(address user, uint256 amount) internal { + vm.startPrank(user); + vault.withdraw(user, amount); + vm.stopPrank(); + } +} diff --git a/test/integration/SymbioticCoreIntegration.sol b/test/integration/SymbioticCoreIntegration.sol index 37525604..5431e41a 100644 --- a/test/integration/SymbioticCoreIntegration.sol +++ b/test/integration/SymbioticCoreIntegration.sol @@ -363,8 +363,9 @@ contract SymbioticCoreIntegration is SymbioticCoreInit { isPossibleOperatorForSubnetwork[ subnetwork ][vaults_SymbioticCore[k]][operators_SymbioticCore[l].addr] = true; - possibleOperatorsForSubnetwork[subnetwork][vaults_SymbioticCore[k]] - .push(operators_SymbioticCore[l].addr); + possibleOperatorsForSubnetwork[subnetwork][vaults_SymbioticCore[k]].push( + operators_SymbioticCore[l].addr + ); } if (_operatorConfirmedValidating_SymbioticCore( operators_SymbioticCore[l].addr, vaults_SymbioticCore[k], subnetwork @@ -372,8 +373,9 @@ contract SymbioticCoreIntegration is SymbioticCoreInit { isConfirmedOperatorForSubnetwork[ subnetwork ][vaults_SymbioticCore[k]][operators_SymbioticCore[l].addr] = true; - confirmedOperatorsForSubnetwork[subnetwork][vaults_SymbioticCore[k]] - .push(operators_SymbioticCore[l].addr); + confirmedOperatorsForSubnetwork[subnetwork][vaults_SymbioticCore[k]].push( + operators_SymbioticCore[l].addr + ); } } } diff --git a/test/integration/base/SymbioticCoreBindingsBase.sol b/test/integration/base/SymbioticCoreBindingsBase.sol index e8f6fecd..8e2dba8f 100644 --- a/test/integration/base/SymbioticCoreBindingsBase.sol +++ b/test/integration/base/SymbioticCoreBindingsBase.sol @@ -88,11 +88,11 @@ abstract contract SymbioticCoreBindingsBase is Test { _optInVault_SymbioticCore(symbioticCore, who, who, vault, deadline, signature); } - function _optInNetwork_SymbioticCore( - SymbioticCoreConstants.Core memory symbioticCore, - address who, - address network - ) internal virtual broadcast(who) { + function _optInNetwork_SymbioticCore(SymbioticCoreConstants.Core memory symbioticCore, address who, address network) + internal + virtual + broadcast(who) + { symbioticCore.operatorNetworkOptInService.optIn(network); } diff --git a/test/integration/base/SymbioticCoreInitBase.sol b/test/integration/base/SymbioticCoreInitBase.sol index e685cdf0..6e1792c6 100644 --- a/test/integration/base/SymbioticCoreInitBase.sol +++ b/test/integration/base/SymbioticCoreInitBase.sol @@ -610,9 +610,9 @@ abstract contract SymbioticCoreInitBase is SymbioticUtils, SymbioticCoreBindings } else if (type_ == 2) { delegatorSpecificCondition = ISymbioticOperatorSpecificDelegator(delegator).networkLimit(subnetwork) > 0; } else if (type_ == 3) { - delegatorSpecificCondition = - ISymbioticOperatorNetworkSpecificDelegator(delegator).network() == subnetwork.network() - && ISymbioticOperatorNetworkSpecificDelegator(delegator).maxNetworkLimit(subnetwork) > 0; + delegatorSpecificCondition = ISymbioticOperatorNetworkSpecificDelegator(delegator).network() + == subnetwork.network() + && ISymbioticOperatorNetworkSpecificDelegator(delegator).maxNetworkLimit(subnetwork) > 0; } return delegatorSpecificCondition; diff --git a/ui/.gitignore b/ui/.gitignore new file mode 100644 index 00000000..a547bf36 --- /dev/null +++ b/ui/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/ui/README.md b/ui/README.md new file mode 100644 index 00000000..d2e77611 --- /dev/null +++ b/ui/README.md @@ -0,0 +1,73 @@ +# React + TypeScript + Vite + +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. + +Currently, two official plugins are available: + +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) (or [oxc](https://oxc.rs) when used in [rolldown-vite](https://vite.dev/guide/rolldown)) for Fast Refresh +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh + +## React Compiler + +The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation). + +## Expanding the ESLint configuration + +If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules: + +```js +export default defineConfig([ + globalIgnores(['dist']), + { + files: ['**/*.{ts,tsx}'], + extends: [ + // Other configs... + + // Remove tseslint.configs.recommended and replace with this + tseslint.configs.recommendedTypeChecked, + // Alternatively, use this for stricter rules + tseslint.configs.strictTypeChecked, + // Optionally, add this for stylistic rules + tseslint.configs.stylisticTypeChecked, + + // Other configs... + ], + languageOptions: { + parserOptions: { + project: ['./tsconfig.node.json', './tsconfig.app.json'], + tsconfigRootDir: import.meta.dirname, + }, + // other options... + }, + }, +]) +``` + +You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules: + +```js +// eslint.config.js +import reactX from 'eslint-plugin-react-x' +import reactDom from 'eslint-plugin-react-dom' + +export default defineConfig([ + globalIgnores(['dist']), + { + files: ['**/*.{ts,tsx}'], + extends: [ + // Other configs... + // Enable lint rules for React + reactX.configs['recommended-typescript'], + // Enable lint rules for React DOM + reactDom.configs.recommended, + ], + languageOptions: { + parserOptions: { + project: ['./tsconfig.node.json', './tsconfig.app.json'], + tsconfigRootDir: import.meta.dirname, + }, + // other options... + }, + }, +]) +``` diff --git a/ui/eslint.config.js b/ui/eslint.config.js new file mode 100644 index 00000000..5e6b472f --- /dev/null +++ b/ui/eslint.config.js @@ -0,0 +1,23 @@ +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' +import tseslint from 'typescript-eslint' +import { defineConfig, globalIgnores } from 'eslint/config' + +export default defineConfig([ + globalIgnores(['dist']), + { + files: ['**/*.{ts,tsx}'], + extends: [ + js.configs.recommended, + tseslint.configs.recommended, + reactHooks.configs.flat.recommended, + reactRefresh.configs.vite, + ], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + }, + }, +]) diff --git a/ui/index.html b/ui/index.html new file mode 100644 index 00000000..592716ba --- /dev/null +++ b/ui/index.html @@ -0,0 +1,13 @@ + + + + + + + ui + + +
+ + + diff --git a/ui/package.json b/ui/package.json new file mode 100644 index 00000000..cbf0bcba --- /dev/null +++ b/ui/package.json @@ -0,0 +1,43 @@ +{ + "name": "ui", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "@privy-io/react-auth": "^3.9.0", + "@privy-io/wagmi": "^2.1.1", + "@tailwindcss/vite": "^4.1.18", + "@tanstack/react-query": "^5.90.12", + "react": "^19.2.0", + "react-dom": "^19.2.0", + "tailwindcss": "^4.1.18", + "viem": "~2.41.2", + "wagmi": "^3.1.0" + }, + "devDependencies": { + "@eslint/js": "^9.39.1", + "@types/node": "^24.10.1", + "@types/react": "^19.2.5", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^5.1.1", + "daisyui": "^5.5.14", + "eslint": "^9.39.1", + "eslint-plugin-react-hooks": "^7.0.1", + "eslint-plugin-react-refresh": "^0.4.24", + "globals": "^16.5.0", + "typescript": "~5.9.3", + "typescript-eslint": "^8.46.4", + "vite": "npm:rolldown-vite@7.2.5" + }, + "pnpm": { + "overrides": { + "vite": "npm:rolldown-vite@7.2.5" + } + } +} diff --git a/ui/public/vite.svg b/ui/public/vite.svg new file mode 100644 index 00000000..e7b8dfb1 --- /dev/null +++ b/ui/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ui/src/App.css b/ui/src/App.css new file mode 100644 index 00000000..b9d355df --- /dev/null +++ b/ui/src/App.css @@ -0,0 +1,42 @@ +#root { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; +} + +.logo { + height: 6em; + padding: 1.5em; + will-change: filter; + transition: filter 300ms; +} +.logo:hover { + filter: drop-shadow(0 0 2em #646cffaa); +} +.logo.react:hover { + filter: drop-shadow(0 0 2em #61dafbaa); +} + +@keyframes logo-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +@media (prefers-reduced-motion: no-preference) { + a:nth-of-type(2) .logo { + animation: logo-spin infinite 20s linear; + } +} + +.card { + padding: 2em; +} + +.read-the-docs { + color: #888; +} diff --git a/ui/src/App.tsx b/ui/src/App.tsx new file mode 100644 index 00000000..cba07a57 --- /dev/null +++ b/ui/src/App.tsx @@ -0,0 +1,5 @@ +import { UniversalDelegatorConfigurator } from './pages/UniversalDelegatorConfigurator' + +export default function App() { + return +} diff --git a/ui/src/Providers.tsx b/ui/src/Providers.tsx new file mode 100644 index 00000000..eb0dd821 --- /dev/null +++ b/ui/src/Providers.tsx @@ -0,0 +1,21 @@ +import { PrivyProvider } from '@privy-io/react-auth' +import { WagmiProvider } from '@privy-io/wagmi' +import { QueryClient, QueryClientProvider } from '@tanstack/react-query' +import type { ReactNode } from 'react' + +import { wagmiConfig } from './web3/config' + +const queryClient = new QueryClient() + +export function Providers({ children }: { children: ReactNode }) { + const appId = import.meta.env.VITE_PRIVY_APP_ID ?? 'cmj9pcima056qjs0chfowelqx' + + return ( + + + {children} + + + ) +} + diff --git a/ui/src/assets/react.svg b/ui/src/assets/react.svg new file mode 100644 index 00000000..6c87de9b --- /dev/null +++ b/ui/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ui/src/contracts/universalDelegator.ts b/ui/src/contracts/universalDelegator.ts new file mode 100644 index 00000000..b157ad86 --- /dev/null +++ b/ui/src/contracts/universalDelegator.ts @@ -0,0 +1,289 @@ +export const universalDelegatorAbi = [ + { + type: 'function', + name: 'slots', + stateMutability: 'view', + inputs: [{ name: 'index', type: 'uint96' }], + outputs: [ + { + name: 'size', + type: 'tuple', + components: [ + { + name: '_trace', + type: 'tuple', + components: [ + { + name: '_checkpoints', + type: 'tuple[]', + components: [ + { name: '_key', type: 'uint48' }, + { name: '_value', type: 'uint208' }, + ], + }, + ], + }, + { name: '_values', type: 'uint256[]' }, + ], + }, + { + name: 'prevSum', + type: 'tuple', + components: [ + { + name: '_trace', + type: 'tuple', + components: [ + { + name: '_checkpoints', + type: 'tuple[]', + components: [ + { name: '_key', type: 'uint48' }, + { name: '_value', type: 'uint208' }, + ], + }, + ], + }, + { name: '_values', type: 'uint256[]' }, + ], + }, + { + name: 'isShared', + type: 'tuple', + components: [ + { + name: '_trace', + type: 'tuple', + components: [ + { + name: '_checkpoints', + type: 'tuple[]', + components: [ + { name: '_key', type: 'uint48' }, + { name: '_value', type: 'uint208' }, + ], + }, + ], + }, + ], + }, + { + name: 'pendingFreeCumulative', + type: 'tuple', + components: [ + { + name: '_trace', + type: 'tuple', + components: [ + { + name: '_checkpoints', + type: 'tuple[]', + components: [ + { name: '_key', type: 'uint48' }, + { name: '_value', type: 'uint208' }, + ], + }, + ], + }, + { name: '_values', type: 'uint256[]' }, + ], + }, + ], + }, + { + type: 'function', + name: 'getBalance', + stateMutability: 'view', + inputs: [{ name: 'index', type: 'uint96' }], + outputs: [{ name: 'balance', type: 'uint256' }], + }, + { + type: 'function', + name: 'getAllocated', + stateMutability: 'view', + inputs: [{ name: 'index', type: 'uint96' }], + outputs: [{ name: 'allocated', type: 'uint256' }], + }, + { + type: 'function', + name: 'getAvailable', + stateMutability: 'view', + inputs: [{ name: 'index', type: 'uint96' }], + outputs: [{ name: 'available', type: 'uint256' }], + }, + { + type: 'function', + name: 'multicall', + stateMutability: 'nonpayable', + inputs: [{ name: 'data', type: 'bytes[]' }], + outputs: [{ name: 'results', type: 'bytes[]' }], + }, + { + type: 'function', + name: 'createSlot', + stateMutability: 'nonpayable', + inputs: [ + { name: 'parentIndex', type: 'uint96' }, + { name: 'isShared', type: 'bool' }, + { name: 'size', type: 'uint256' }, + ], + outputs: [], + }, + { + type: 'function', + name: 'setIsShared', + stateMutability: 'nonpayable', + inputs: [ + { name: 'index', type: 'uint96' }, + { name: 'isShared', type: 'bool' }, + ], + outputs: [], + }, + { + type: 'function', + name: 'setSize', + stateMutability: 'nonpayable', + inputs: [ + { name: 'index', type: 'uint96' }, + { name: 'size', type: 'uint256' }, + ], + outputs: [], + }, + { + type: 'function', + name: 'swapSlots', + stateMutability: 'nonpayable', + inputs: [ + { name: 'index1', type: 'uint96' }, + { name: 'index2', type: 'uint96' }, + ], + outputs: [], + }, + { + type: 'function', + name: 'assignNetwork', + stateMutability: 'nonpayable', + inputs: [ + { name: 'index', type: 'uint96' }, + { name: 'subnetwork', type: 'bytes32' }, + ], + outputs: [], + }, + { + type: 'function', + name: 'unassignNetwork', + stateMutability: 'nonpayable', + inputs: [{ name: 'subnetwork', type: 'bytes32' }], + outputs: [], + }, + { + type: 'function', + name: 'assignOperator', + stateMutability: 'nonpayable', + inputs: [ + { name: 'index', type: 'uint96' }, + { name: 'operator', type: 'address' }, + ], + outputs: [], + }, + { + type: 'function', + name: 'unassignOperator', + stateMutability: 'nonpayable', + inputs: [ + { name: 'parentIndex', type: 'uint96' }, + { name: 'operator', type: 'address' }, + ], + outputs: [], + }, + { type: 'error', name: 'NotEnoughAvailable', inputs: [] }, + { type: 'error', name: 'NotSameParent', inputs: [] }, + { type: 'error', name: 'WrongOrder', inputs: [] }, + { type: 'error', name: 'NotSameAllocated', inputs: [] }, + { type: 'error', name: 'PartiallyAllocated', inputs: [] }, + { type: 'error', name: 'NetworkAlreadyAssigned', inputs: [] }, + { type: 'error', name: 'NetworkNotAssigned', inputs: [] }, + { type: 'error', name: 'OperatorAlreadyAssigned', inputs: [] }, + { type: 'error', name: 'OperatorNotAssigned', inputs: [] }, + { type: 'error', name: 'SlotAllocated', inputs: [] }, + { type: 'error', name: 'MissingRoleHolders', inputs: [] }, + { type: 'error', name: 'IsSharedNotChanged', inputs: [] }, + { type: 'error', name: 'WrongDepth', inputs: [] }, + { + type: 'error', + name: 'AccessControlUnauthorizedAccount', + inputs: [ + { name: 'account', type: 'address' }, + { name: 'role', type: 'bytes32' }, + ], + }, + { + type: 'event', + name: 'CreateSlot', + inputs: [ + { name: 'index', type: 'uint96', indexed: true }, + { name: 'size', type: 'uint256', indexed: false }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'SetIsShared', + inputs: [ + { name: 'index', type: 'uint96', indexed: true }, + { name: 'isShared', type: 'bool', indexed: false }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'SetSize', + inputs: [ + { name: 'index', type: 'uint96', indexed: true }, + { name: 'size', type: 'uint256', indexed: false }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'SwapSlots', + inputs: [ + { name: 'index1', type: 'uint96', indexed: true }, + { name: 'index2', type: 'uint96', indexed: true }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'AssignNetwork', + inputs: [ + { name: 'index', type: 'uint96', indexed: true }, + { name: 'subnetwork', type: 'bytes32', indexed: true }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'UnassignNetwork', + inputs: [{ name: 'subnetwork', type: 'bytes32', indexed: true }], + anonymous: false, + }, + { + type: 'event', + name: 'AssignOperator', + inputs: [ + { name: 'index', type: 'uint96', indexed: true }, + { name: 'operator', type: 'address', indexed: true }, + ], + anonymous: false, + }, + { + type: 'event', + name: 'UnassignOperator', + inputs: [ + { name: 'index', type: 'uint96', indexed: true }, + { name: 'operator', type: 'address', indexed: true }, + ], + anonymous: false, + }, +] as const diff --git a/ui/src/index.css b/ui/src/index.css new file mode 100644 index 00000000..0b112958 --- /dev/null +++ b/ui/src/index.css @@ -0,0 +1,8 @@ +@config '../tailwind.config.ts'; +@import 'tailwindcss'; + +html, +body, +#root { + height: 100%; +} diff --git a/ui/src/main.tsx b/ui/src/main.tsx new file mode 100644 index 00000000..fa43ddd3 --- /dev/null +++ b/ui/src/main.tsx @@ -0,0 +1,13 @@ +import { StrictMode } from 'react' +import { createRoot } from 'react-dom/client' +import './index.css' +import App from './App.tsx' +import { Providers } from './Providers.tsx' + +createRoot(document.getElementById('root')!).render( + + + + + , +) diff --git a/ui/src/pages/UniversalDelegatorConfigurator.tsx b/ui/src/pages/UniversalDelegatorConfigurator.tsx new file mode 100644 index 00000000..fe23e57b --- /dev/null +++ b/ui/src/pages/UniversalDelegatorConfigurator.tsx @@ -0,0 +1,3459 @@ +import { usePrivy } from "@privy-io/react-auth"; +import { useCallback, useEffect, useMemo, useRef, useState, type CSSProperties, type MouseEvent } from "react"; +import { useAccount, usePublicClient, useReadContracts, useWaitForTransactionReceipt, useWriteContract } from "wagmi"; +import { + type Address, + BaseError, + ContractFunctionRevertedError, + type Hex, + type PublicClient, + decodeEventLog, + encodeFunctionData, + getEventSelector, + isAddress, + isHex, + padHex, +} from "viem"; + +import { universalDelegatorAbi } from "../contracts/universalDelegator"; +import { createIndex, formatIndex, getChildIndex, getDepth, getParentIndex } from "../utils/universalDelegatorIndex"; + +const UNIVERSAL_DELEGATOR_EVENT_ABI = universalDelegatorAbi.filter((item) => item.type === "event") as unknown as Array< + (typeof universalDelegatorAbi)[number] +>; + +const UNIVERSAL_DELEGATOR_EVENT_TOPICS = new Set( + UNIVERSAL_DELEGATOR_EVENT_ABI.map((event) => getEventSelector(event as never)), +); + +type SlotSizeInput = string; + +type DraftState = { + draft: T; + synced: T | null; +}; + +type GroupDraft = { size: SlotSizeInput; isShared: boolean }; +type NetworkDraft = { size: SlotSizeInput; subnetwork: string }; +type OperatorDraft = { size: SlotSizeInput; operator: string }; + +type OperatorSlot = { + id: string; + index: bigint | null; + state: DraftState; +}; + +type NetworkSlot = { + id: string; + index: bigint | null; + state: DraftState; + operators: OperatorSlot[]; +}; + +type GroupSlot = { + id: string; + index: bigint | null; + state: DraftState; + networks: NetworkSlot[]; +}; + +type UniversalDelegatorModel = { + groups: GroupSlot[]; +}; + +type ZoomState = + | { kind: "all" } + | { kind: "group"; groupId: string } + | { kind: "network"; groupId: string; networkId: string }; + +type GroupConstructor = "shared-multi" | "shared-single" | "single-multi" | "single-single"; + +type UdOperation = + | { kind: "createSlot"; parentIndex: bigint; isShared: boolean; size: bigint; slotId?: string } + | { kind: "setIsShared"; index: bigint; isShared: boolean } + | { kind: "setSize"; index: bigint; size: bigint } + | { kind: "swapSlots"; index1: bigint; index2: bigint } + | { kind: "assignNetwork"; index: bigint; subnetwork: Hex } + | { kind: "unassignNetwork"; subnetwork: Hex } + | { kind: "assignOperator"; index: bigint; operator: Address } + | { kind: "unassignOperator"; parentIndex: bigint; operator: Address }; + +function parseUint(value: string): bigint | null { + const normalized = value.trim(); + if (!normalized) return 0n; + try { + const parsed = BigInt(normalized); + if (parsed < 0n) return null; + return parsed; + } catch { + return null; + } +} + +function parseBytes32(value: string): Hex | null { + const v = value.trim(); + if (!v) return null; + + if (!v.startsWith("0x")) return null; + if (!isHex(v)) return null; + if (v.length > 66) return null; + return padHex(v, { size: 32, dir: "right" }); +} + +type HasSize = { size: SlotSizeInput }; + +function effectiveSize(state: DraftState): bigint { + const draft = parseUint(state.draft.size); + if (draft !== null) return draft; + const synced = state.synced ? parseUint(state.synced.size) : null; + return synced ?? 0n; +} + +function sumBigints(values: bigint[]): bigint { + let total = 0n; + for (const v of values) total += v; + return total; +} + +function maxBigint(values: bigint[]): bigint { + let m = 0n; + for (const v of values) if (v > m) m = v; + return m; +} + +const FILL_OPACITY = 0.2; + +function pendingPatternStyle(colorVar: string): CSSProperties { + const lineColor = `var(${colorVar})`; + return { + backgroundImage: `linear-gradient(${lineColor} 0 2px, transparent 2px 10px), linear-gradient(90deg, ${lineColor} 0 2px, transparent 2px 10px)`, + backgroundSize: "10px 10px", + backgroundPosition: "-1px -1px", + backgroundRepeat: "repeat", + opacity: FILL_OPACITY, + }; +} + +function allocatedFillStyle(colorVar: string): CSSProperties { + return { backgroundColor: `var(${colorVar})`, opacity: FILL_OPACITY }; +} + +function isInteractiveTarget(target: EventTarget | null): boolean { + const element = target as HTMLElement | null; + if (!element || typeof element.closest !== "function") return false; + return Boolean(element.closest("button, input, textarea, select, label, a, [data-no-zoom]")); +} + +function formatShortAddress(address: string): string { + if (address.length <= 10) return address; + return `${address.slice(0, 6)}...${address.slice(-4)}`; +} + +function parsePositiveInt(value: string): number | null { + const trimmed = value.trim(); + if (!trimmed) return null; + const parsed = Number(trimmed); + if (!Number.isFinite(parsed) || !Number.isInteger(parsed) || parsed <= 0) return null; + return parsed; +} + +function cloneOps(values: UdOperation[]): UdOperation[] { + return values.map((op) => ({ ...op })); +} + +function cloneModel(values: UniversalDelegatorModel): UniversalDelegatorModel { + return { + groups: values.groups.map((group) => ({ + id: group.id, + index: group.index, + state: { + draft: { ...group.state.draft }, + synced: group.state.synced ? { ...group.state.synced } : null, + }, + networks: group.networks.map((network) => ({ + id: network.id, + index: network.index, + state: { + draft: { ...network.state.draft }, + synced: network.state.synced ? { ...network.state.synced } : null, + }, + operators: network.operators.map((operator) => ({ + id: operator.id, + index: operator.index, + state: { + draft: { ...operator.state.draft }, + synced: operator.state.synced ? { ...operator.state.synced } : null, + }, + })), + })), + })), + }; +} + +type OnchainSlotSnapshot = { size: bigint; isShared: boolean }; + +function latestTrace208Value(trace: unknown): bigint { + const checkpoints = (trace as { _trace?: { _checkpoints?: Array<{ _value: bigint }> } })?._trace?._checkpoints; + if (!checkpoints || checkpoints.length === 0) return 0n; + return checkpoints[checkpoints.length - 1]?._value ?? 0n; +} + +function ensureChildren(map: Map, parentIndex: bigint): bigint[] { + const existing = map.get(parentIndex); + if (existing) return existing; + const created: bigint[] = []; + map.set(parentIndex, created); + return created; +} + +function bigintMin(a: bigint, b: bigint): bigint { + return a < b ? a : b; +} + +function bigintMax(a: bigint, b: bigint): bigint { + return a > b ? a : b; +} + +function saturatingSub(a: bigint, b: bigint): bigint { + return a > b ? a - b : 0n; +} + +function computeSlotIdToIndex(model: UniversalDelegatorModel): Map { + const idToIndex = new Map(); + + let maxGroupChild = 0n; + for (const group of model.groups) { + if (group.index === null) continue; + maxGroupChild = bigintMax(maxGroupChild, getChildIndex(group.index)); + } + let nextGroupChild = maxGroupChild + 1n; + + for (const group of model.groups) { + const groupIndex = group.index ?? createIndex(0n, nextGroupChild++); + idToIndex.set(group.id, groupIndex); + + let maxNetworkChild = 0n; + for (const network of group.networks) { + if (network.index === null) continue; + maxNetworkChild = bigintMax(maxNetworkChild, getChildIndex(network.index)); + } + let nextNetworkChild = maxNetworkChild + 1n; + + for (const network of group.networks) { + const networkIndex = network.index ?? createIndex(groupIndex, nextNetworkChild++); + idToIndex.set(network.id, networkIndex); + + let maxOperatorChild = 0n; + for (const operator of network.operators) { + if (operator.index === null) continue; + maxOperatorChild = bigintMax(maxOperatorChild, getChildIndex(operator.index)); + } + let nextOperatorChild = maxOperatorChild + 1n; + + for (const operator of network.operators) { + const operatorIndex = operator.index ?? createIndex(networkIndex, nextOperatorChild++); + idToIndex.set(operator.id, operatorIndex); + } + } + } + + return idToIndex; +} + +function computeSimulatedAllocations( + model: UniversalDelegatorModel, + slotIdToIndex: Map, + rootActiveStake: bigint | null, +): Map { + const allocatedByIndex = new Map(); + const rootBalance = rootActiveStake ?? 0n; + allocatedByIndex.set("0", rootBalance); + + let groupPrevSum = 0n; + for (const group of model.groups) { + const groupSize = effectiveSize(group.state); + const groupAllocated = bigintMin(saturatingSub(rootBalance, groupPrevSum), groupSize); + const groupIndex = slotIdToIndex.get(group.id); + if (groupIndex !== undefined) allocatedByIndex.set(groupIndex.toString(), groupAllocated); + groupPrevSum += groupSize; + + const groupIsShared = group.state.draft.isShared; + let networkPrevSum = 0n; + for (const network of group.networks) { + const networkSize = effectiveSize(network.state); + const networkAllocated = groupIsShared + ? bigintMin(groupAllocated, networkSize) + : bigintMin(saturatingSub(groupAllocated, networkPrevSum), networkSize); + const networkIndex = slotIdToIndex.get(network.id); + if (networkIndex !== undefined) allocatedByIndex.set(networkIndex.toString(), networkAllocated); + networkPrevSum += networkSize; + + let operatorPrevSum = 0n; + for (const operator of network.operators) { + const operatorSize = effectiveSize(operator.state); + const operatorAllocated = bigintMin(saturatingSub(networkAllocated, operatorPrevSum), operatorSize); + const operatorIndex = slotIdToIndex.get(operator.id); + if (operatorIndex !== undefined) allocatedByIndex.set(operatorIndex.toString(), operatorAllocated); + operatorPrevSum += operatorSize; + } + } + } + + return allocatedByIndex; +} + +function computePendingByIndex(params: { + model: UniversalDelegatorModel; + slotIdToIndex: Map; + baselineSlotIdToIndex: Map; + baselineAllocationsByIndex: Map; +}): Map { + const pendingByIndex = new Map(); + const baselineAllocations = params.baselineAllocationsByIndex; + const baselineIndices = params.baselineSlotIdToIndex; + + const baselineAllocatedFor = (slotId: string): bigint => { + const baselineIndex = baselineIndices.get(slotId); + if (baselineIndex === undefined) return 0n; + return baselineAllocations.get(baselineIndex.toString()) ?? 0n; + }; + + let rootPending = 0n; + for (const group of params.model.groups) { + let groupPending = 0n; + for (const network of group.networks) { + let networkPending = 0n; + for (const operator of network.operators) { + const operatorIndex = params.slotIdToIndex.get(operator.id); + if (operatorIndex !== undefined) pendingByIndex.set(operatorIndex.toString(), 0n); + + const baselineAllocated = baselineAllocatedFor(operator.id); + const nextSize = effectiveSize(operator.state); + if (baselineAllocated > nextSize) { + networkPending += baselineAllocated - nextSize; + } + } + + const networkIndex = params.slotIdToIndex.get(network.id); + if (networkIndex !== undefined) pendingByIndex.set(networkIndex.toString(), networkPending); + + const baselineAllocated = baselineAllocatedFor(network.id); + const nextSize = effectiveSize(network.state); + if (baselineAllocated > nextSize) { + groupPending += baselineAllocated - nextSize; + } + } + + const groupIndex = params.slotIdToIndex.get(group.id); + if (groupIndex !== undefined) pendingByIndex.set(groupIndex.toString(), groupPending); + + const baselineAllocated = baselineAllocatedFor(group.id); + const nextSize = effectiveSize(group.state); + if (baselineAllocated > nextSize) { + rootPending += baselineAllocated - nextSize; + } + } + + pendingByIndex.set("0", rootPending); + return pendingByIndex; +} + +function computeSimulatedAllocationsFromStateWithPending( + state: SimState, + rootBalance: bigint, + pendingByIndex: Map, +): Map { + const allocated = new Map(); + allocated.set(0n, rootBalance); + + const walk = (parentIndex: bigint) => { + const children = state.children.get(parentIndex) ?? []; + const parentAllocated = allocated.get(parentIndex) ?? 0n; + const parentPending = pendingByIndex.get(parentIndex) ?? 0n; + const parentAvailable = saturatingSub(parentAllocated, parentPending); + const parentSlot = state.slots.get(parentIndex); + const parentIsShared = parentIndex === 0n ? false : (parentSlot?.isShared ?? false); + + let prevSum = 0n; + for (const child of children) { + const childSlot = state.slots.get(child) ?? { size: 0n, isShared: false }; + const childAllocated = parentIsShared + ? bigintMin(parentAvailable, childSlot.size) + : bigintMin(saturatingSub(parentAvailable, prevSum), childSlot.size); + allocated.set(child, childAllocated); + prevSum += childSlot.size; + walk(child); + } + }; + + walk(0n); + return allocated; +} + +function computePendingByIndexFromOps(params: { + baselineModel: UniversalDelegatorModel; + ops: UdOperation[]; + rootActiveStake: bigint | null; + baselinePendingByIndex?: Map | null; +}): Map { + if (params.ops.length === 0) return new Map(); + + const state = buildSimStateFromModel(params.baselineModel); + const pendingByIndex = new Map(); + if (params.baselinePendingByIndex) { + for (const [key, value] of params.baselinePendingByIndex.entries()) { + if (value <= 0n) continue; + try { + pendingByIndex.set(BigInt(key), value); + } catch { + // ignore invalid pending keys + } + } + } + const rootBalance = params.rootActiveStake ?? 0n; + + const addPending = (index: bigint, delta: bigint) => { + if (delta <= 0n) return; + pendingByIndex.set(index, (pendingByIndex.get(index) ?? 0n) + delta); + }; + + for (const op of params.ops) { + if (op.kind === "createSlot") { + const local = state.nextChildLocalIndex.get(op.parentIndex) ?? 1n; + let index: bigint; + try { + index = createIndex(op.parentIndex, local); + } catch { + return new Map(); + } + + state.nextChildLocalIndex.set(op.parentIndex, local + 1n); + state.created.add(index); + state.slots.set(index, { size: op.size, isShared: op.isShared }); + + if (!state.children.has(op.parentIndex)) state.children.set(op.parentIndex, []); + state.children.get(op.parentIndex)!.push(index); + if (!state.children.has(index)) state.children.set(index, []); + continue; + } + + if (op.kind === "setIsShared") { + const prev = state.slots.get(op.index) ?? { size: 0n, isShared: false }; + state.slots.set(op.index, { ...prev, isShared: op.isShared }); + continue; + } + + if (op.kind === "setSize") { + const prev = state.slots.get(op.index) ?? { size: 0n, isShared: false }; + if (op.size < prev.size) { + const allocated = computeSimulatedAllocationsFromStateWithPending(state, rootBalance, pendingByIndex); + const allocatedNow = allocated.get(op.index) ?? 0n; + if (allocatedNow > op.size) { + addPending(getParentIndex(op.index), allocatedNow - op.size); + } + } + state.slots.set(op.index, { ...prev, size: op.size }); + continue; + } + + if (op.kind === "swapSlots") { + const parent = getParentIndex(op.index1); + const list = state.children.get(parent); + if (!list) return new Map(); + const i1 = list.indexOf(op.index1); + const i2 = list.indexOf(op.index2); + if (i1 === -1 || i2 === -1) return new Map(); + [list[i1], list[i2]] = [list[i2]!, list[i1]!]; + continue; + } + + if (op.kind === "assignNetwork") { + state.networkToSlot.set(op.subnetwork.toLowerCase(), op.index); + continue; + } + + if (op.kind === "unassignNetwork") { + state.networkToSlot.set(op.subnetwork.toLowerCase(), 0n); + continue; + } + + if (op.kind === "assignOperator") { + const parentIndex = getParentIndex(op.index); + const key = `${parentIndex.toString()}:${op.operator.toLowerCase()}`; + state.operatorToSlot.set(key, op.index); + state.operatorBySlot.set(op.index, op.operator); + continue; + } + + const key = `${op.parentIndex.toString()}:${op.operator.toLowerCase()}`; + const currentIndex = state.operatorToSlot.get(key) ?? 0n; + if (currentIndex !== 0n) state.operatorBySlot.delete(currentIndex); + state.operatorToSlot.set(key, 0n); + } + + const result = new Map(); + for (const [index, value] of pendingByIndex.entries()) { + result.set(index.toString(), value); + } + return result; +} + +function computeSimulatedAllocationsWithPending(params: { + model: UniversalDelegatorModel; + slotIdToIndex: Map; + baselineSlotIdToIndex: Map; + baselineAllocationsByIndex: Map; + rootActiveStake: bigint | null; + pendingByIndexOverride?: Map | null; +}): { allocatedByIndex: Map; pendingByIndex: Map } { + const allocatedByIndex = new Map(); + const rootBalance = params.rootActiveStake ?? 0n; + const pendingByIndex = + params.pendingByIndexOverride ?? + computePendingByIndex({ + model: params.model, + slotIdToIndex: params.slotIdToIndex, + baselineSlotIdToIndex: params.baselineSlotIdToIndex, + baselineAllocationsByIndex: params.baselineAllocationsByIndex, + }); + const rootPending = pendingByIndex.get("0") ?? 0n; + const rootAvailable = saturatingSub(rootBalance, rootPending); + + allocatedByIndex.set("0", rootBalance); + + let groupPrevSum = 0n; + for (const group of params.model.groups) { + const groupSize = effectiveSize(group.state); + const groupAllocated = bigintMin(saturatingSub(rootAvailable, groupPrevSum), groupSize); + const groupIndex = params.slotIdToIndex.get(group.id); + if (groupIndex !== undefined) allocatedByIndex.set(groupIndex.toString(), groupAllocated); + groupPrevSum += groupSize; + + const groupIsShared = group.state.draft.isShared; + const groupPending = groupIndex !== undefined ? (pendingByIndex.get(groupIndex.toString()) ?? 0n) : 0n; + const groupAvailable = saturatingSub(groupAllocated, groupPending); + let networkPrevSum = 0n; + for (const network of group.networks) { + const networkSize = effectiveSize(network.state); + const networkAllocated = groupIsShared + ? bigintMin(groupAvailable, networkSize) + : bigintMin(saturatingSub(groupAvailable, networkPrevSum), networkSize); + const networkIndex = params.slotIdToIndex.get(network.id); + if (networkIndex !== undefined) allocatedByIndex.set(networkIndex.toString(), networkAllocated); + networkPrevSum += networkSize; + + const networkPending = networkIndex !== undefined ? (pendingByIndex.get(networkIndex.toString()) ?? 0n) : 0n; + const networkAvailable = saturatingSub(networkAllocated, networkPending); + let operatorPrevSum = 0n; + for (const operator of network.operators) { + const operatorSize = effectiveSize(operator.state); + const operatorAllocated = bigintMin(saturatingSub(networkAvailable, operatorPrevSum), operatorSize); + const operatorIndex = params.slotIdToIndex.get(operator.id); + if (operatorIndex !== undefined) allocatedByIndex.set(operatorIndex.toString(), operatorAllocated); + operatorPrevSum += operatorSize; + } + } + } + + return { allocatedByIndex, pendingByIndex }; +} + +async function reconstructModelFromChain(params: { + delegatorAddress: Address; + publicClient: PublicClient; +}): Promise { + const latestBlock = await params.publicClient.getBlockNumber(); + + const slots = new Map(); + const childrenByParent = new Map(); + const networkBySlot = new Map(); + const subnetworkToSlot = new Map(); + const operatorBySlot = new Map(); + + const chunkSize = 50_000n; + for (let fromBlock = 0n; fromBlock <= latestBlock; fromBlock += chunkSize) { + const toBlock = (() => { + const candidate = fromBlock + chunkSize - 1n; + return candidate > latestBlock ? latestBlock : candidate; + })(); + + const rawLogs = await params.publicClient.getLogs({ + address: params.delegatorAddress, + fromBlock, + toBlock, + }); + + for (const log of rawLogs) { + const topic0 = log.topics?.[0] as string | undefined; + if (!topic0 || !UNIVERSAL_DELEGATOR_EVENT_TOPICS.has(topic0)) continue; + + const decoded = decodeEventLog({ + abi: UNIVERSAL_DELEGATOR_EVENT_ABI as never, + data: log.data, + topics: log.topics, + }); + + if (decoded.eventName === "CreateSlot") { + const args = decoded.args as unknown as { index: bigint; size: bigint }; + const index = args.index; + const size = args.size; + slots.set(index, { size, isShared: false }); + const parentIndex = getParentIndex(index); + ensureChildren(childrenByParent, parentIndex).push(index); + continue; + } + + if (decoded.eventName === "SetSize") { + const args = decoded.args as unknown as { index: bigint; size: bigint }; + const index = args.index; + const size = args.size; + const existing = slots.get(index); + if (existing) slots.set(index, { ...existing, size }); + continue; + } + + if (decoded.eventName === "SetIsShared") { + const args = decoded.args as unknown as { index: bigint; isShared: boolean }; + const index = args.index; + const isShared = args.isShared; + const existing = slots.get(index); + if (existing) slots.set(index, { ...existing, isShared }); + continue; + } + + if (decoded.eventName === "SwapSlots") { + const args = decoded.args as unknown as { index1: bigint; index2: bigint }; + const index1 = args.index1; + const index2 = args.index2; + const parentIndex = getParentIndex(index1); + if (parentIndex !== getParentIndex(index2)) continue; + const siblings = childrenByParent.get(parentIndex); + if (!siblings) continue; + const i1 = siblings.indexOf(index1); + const i2 = siblings.indexOf(index2); + if (i1 === -1 || i2 === -1) continue; + [siblings[i1], siblings[i2]] = [siblings[i2]!, siblings[i1]!]; + continue; + } + + if (decoded.eventName === "AssignNetwork") { + const args = decoded.args as unknown as { index: bigint; subnetwork: Hex }; + const index = args.index; + const subnetwork = args.subnetwork; + const key = subnetwork.toLowerCase(); + subnetworkToSlot.set(key, index); + networkBySlot.set(index, subnetwork); + continue; + } + + if (decoded.eventName === "UnassignNetwork") { + const args = decoded.args as unknown as { subnetwork: Hex }; + const subnetwork = args.subnetwork; + const key = subnetwork.toLowerCase(); + const prevIndex = subnetworkToSlot.get(key); + if (prevIndex !== undefined) networkBySlot.delete(prevIndex); + subnetworkToSlot.delete(key); + continue; + } + + if (decoded.eventName === "AssignOperator") { + const args = decoded.args as unknown as { index: bigint; operator: Address }; + const index = args.index; + const operator = args.operator; + operatorBySlot.set(index, operator); + continue; + } + + if (decoded.eventName === "UnassignOperator") { + const args = decoded.args as unknown as { index: bigint }; + const index = args.index; + operatorBySlot.delete(index); + continue; + } + } + } + + const groupIndices = childrenByParent.get(0n) ?? []; + const applyIsShared = (groupIndex: bigint, slotData: unknown) => { + const slot = slots.get(groupIndex); + if (!slot) return; + const isSharedTrace = + (slotData as { isShared?: unknown })?.isShared ?? (Array.isArray(slotData) ? slotData[2] : undefined); + const isSharedValue = latestTrace208Value(isSharedTrace); + slots.set(groupIndex, { ...slot, isShared: isSharedValue > 0n }); + }; + + if (groupIndices.length > 0) { + const batchSize = 100; + let canUseMulticall = true; + for (let i = 0; i < groupIndices.length; i += batchSize) { + const batch = groupIndices.slice(i, i + batchSize); + if (canUseMulticall) { + try { + const results = await params.publicClient.multicall({ + allowFailure: true, + contracts: batch.map((groupIndex) => ({ + address: params.delegatorAddress, + abi: universalDelegatorAbi, + functionName: "slots", + args: [groupIndex], + })), + }); + results.forEach((result, idx) => { + if (result.status !== "success") return; + const groupIndex = batch[idx]; + if (groupIndex === undefined) return; + applyIsShared(groupIndex, result.result); + }); + continue; + } catch { + canUseMulticall = false; + } + } + + for (const groupIndex of batch) { + const slot = slots.get(groupIndex); + if (!slot) continue; + try { + const slotData = await params.publicClient.readContract({ + abi: universalDelegatorAbi, + address: params.delegatorAddress, + functionName: "slots", + args: [groupIndex], + }); + applyIsShared(groupIndex, slotData); + } catch { + // ignore single-slot failures during reconstruction + } + } + } + } + + const groups: GroupSlot[] = []; + for (const groupIndex of groupIndices) { + const groupSlot = slots.get(groupIndex); + if (!groupSlot) continue; + + const groupDraft: GroupDraft = { size: groupSlot.size.toString(), isShared: groupSlot.isShared }; + const group: GroupSlot = { + id: `group-${formatIndex(groupIndex)}`, + index: groupIndex, + state: { draft: groupDraft, synced: { ...groupDraft } }, + networks: [], + }; + + const networkIndices = childrenByParent.get(groupIndex) ?? []; + for (const networkIndex of networkIndices) { + const networkSlot = slots.get(networkIndex); + if (!networkSlot) continue; + + const subnetwork = networkBySlot.get(networkIndex) ?? ""; + const networkDraft: NetworkDraft = { size: networkSlot.size.toString(), subnetwork }; + const network: NetworkSlot = { + id: `network-${formatIndex(networkIndex)}`, + index: networkIndex, + state: { draft: networkDraft, synced: { ...networkDraft } }, + operators: [], + }; + + const operatorIndices = childrenByParent.get(networkIndex) ?? []; + for (const operatorIndex of operatorIndices) { + const operatorSlot = slots.get(operatorIndex); + if (!operatorSlot) continue; + + const operator = operatorBySlot.get(operatorIndex) ?? ""; + const operatorDraft: OperatorDraft = { size: operatorSlot.size.toString(), operator }; + network.operators.push({ + id: `operator-${formatIndex(operatorIndex)}`, + index: operatorIndex, + state: { draft: operatorDraft, synced: { ...operatorDraft } }, + }); + } + + group.networks.push(network); + } + + groups.push(group); + } + + return { groups }; +} + +function flexGrowFromSize(size: bigint, total: bigint): number { + if (total <= 0n) return 1; + if (size <= 0n) return 0; + const scaled = (size * 1_000_000n) / total; + if (scaled <= 0n) return 0.000001; + return Number(scaled) / 1_000_000; +} + +function percentWidthFromSize(size: bigint, max: bigint, minPct = 40, maxPct = 100): number { + if (max <= 0n) return maxPct; + if (size <= 0n) return minPct; + const scaled = Number((size * 10_000n) / max) / 10_000; + return minPct + scaled * (maxPct - minPct); +} + +function autoSyncAll(model: UniversalDelegatorModel): { model: UniversalDelegatorModel; ops: UdOperation[] } { + const nextModel = cloneModel(model); + const nextOps: UdOperation[] = []; + + for (const group of nextModel.groups) { + // ---------- Group ---------- + { + const draft = group.state.draft; + const size = parseUint(draft.size); + + if (size !== null) { + const synced = group.state.synced; + const syncedSize = synced ? parseUint(synced.size) : null; + const sizeDirty = synced === null || syncedSize === null || syncedSize !== size; + const isDirty = synced === null || synced.isShared !== draft.isShared || sizeDirty; + + if (synced === null || isDirty) { + if (group.index === null) { + const localIndex = BigInt(nextModel.groups.filter((g) => g.index !== null).length + 1); + group.index = createIndex(0n, localIndex); + nextOps.push({ kind: "createSlot", parentIndex: 0n, isShared: draft.isShared, size, slotId: group.id }); + } else { + if (synced && synced.isShared !== draft.isShared) { + nextOps.push({ kind: "setIsShared", index: group.index, isShared: draft.isShared }); + } + if (synced && sizeDirty) { + nextOps.push({ kind: "setSize", index: group.index, size }); + } + } + group.state.synced = { ...draft }; + } + } + } + + // ---------- Networks ---------- + for (const network of group.networks) { + const draft = network.state.draft; + const size = parseUint(draft.size); + if (size === null) continue; + if (group.index === null) continue; + + const subnetworkTrimmed = draft.subnetwork.trim(); + const subnetworkParsed = subnetworkTrimmed === "" ? null : parseBytes32(subnetworkTrimmed); + const subnetworkValid = subnetworkTrimmed === "" || subnetworkParsed !== null; + + const synced = network.state.synced; + const syncedSize = synced ? parseUint(synced.size) : null; + const isSizeDirty = synced === null || syncedSize === null || syncedSize !== size; + const isSubnetworkDirty = + subnetworkValid && (synced === null || synced.subnetwork.trim() !== subnetworkTrimmed); + + if (synced === null || isSizeDirty || isSubnetworkDirty) { + if (network.index === null) { + const localIndex = BigInt(group.networks.filter((n) => n.index !== null).length + 1); + network.index = createIndex(group.index, localIndex); + nextOps.push({ + kind: "createSlot", + parentIndex: group.index, + isShared: false, + size, + slotId: network.id, + }); + if (subnetworkParsed) { + nextOps.push({ kind: "assignNetwork", index: network.index, subnetwork: subnetworkParsed }); + } + } else { + if (synced && isSizeDirty) { + nextOps.push({ kind: "setSize", index: network.index, size }); + } + + if (synced && isSubnetworkDirty) { + const prevTrimmed = synced.subnetwork.trim(); + const nextTrimmed = subnetworkTrimmed; + if (prevTrimmed !== nextTrimmed) { + const prevParsed = prevTrimmed === "" ? null : parseBytes32(prevTrimmed); + if (prevParsed) nextOps.push({ kind: "unassignNetwork", subnetwork: prevParsed }); + if (subnetworkParsed) { + nextOps.push({ kind: "assignNetwork", index: network.index, subnetwork: subnetworkParsed }); + } + } + } + } + + if (synced === null) { + network.state.synced = { + ...draft, + subnetwork: subnetworkValid ? draft.subnetwork : "", + }; + } else { + network.state.synced = { + size: draft.size, + subnetwork: subnetworkValid ? draft.subnetwork : synced.subnetwork, + }; + } + } + + if (network.index === null) continue; + + // ---------- Operators ---------- + for (const operator of network.operators) { + const draftOp = operator.state.draft; + const sizeOp = parseUint(draftOp.size); + if (sizeOp === null) continue; + + const operatorTrimmed = draftOp.operator.trim(); + const operatorValid = operatorTrimmed === "" || isAddress(operatorTrimmed); + + const syncedOp = operator.state.synced; + const syncedSize = syncedOp ? parseUint(syncedOp.size) : null; + const isSizeDirtyOp = syncedOp === null || syncedSize === null || syncedSize !== sizeOp; + const isOperatorDirtyOp = + operatorValid && + (syncedOp === null || syncedOp.operator.trim().toLowerCase() !== operatorTrimmed.toLowerCase()); + + if (syncedOp !== null && !isSizeDirtyOp && !isOperatorDirtyOp) continue; + + if (operator.index === null) { + const localIndex = BigInt(network.operators.filter((o) => o.index !== null).length + 1); + operator.index = createIndex(network.index, localIndex); + nextOps.push({ + kind: "createSlot", + parentIndex: network.index, + isShared: false, + size: sizeOp, + slotId: operator.id, + }); + if (operatorValid && operatorTrimmed) { + nextOps.push({ kind: "assignOperator", index: operator.index, operator: operatorTrimmed as Address }); + } + } else { + if (syncedOp && isSizeDirtyOp) { + nextOps.push({ kind: "setSize", index: operator.index, size: sizeOp }); + } + + if (syncedOp && isOperatorDirtyOp) { + const prevTrimmed = syncedOp.operator.trim(); + const nextTrimmed = operatorTrimmed; + if (prevTrimmed.toLowerCase() !== nextTrimmed.toLowerCase()) { + if (prevTrimmed && isAddress(prevTrimmed)) { + nextOps.push({ + kind: "unassignOperator", + parentIndex: network.index, + operator: prevTrimmed as Address, + }); + } + if (nextTrimmed) { + nextOps.push({ kind: "assignOperator", index: operator.index, operator: nextTrimmed as Address }); + } + } + } + } + + if (syncedOp === null) { + operator.state.synced = { ...draftOp, operator: operatorValid ? draftOp.operator : "" }; + } else { + operator.state.synced = { + size: draftOp.size, + operator: operatorValid ? draftOp.operator : syncedOp.operator, + }; + } + } + } + } + + return { model: nextModel, ops: nextOps }; +} + +type SimSlot = { size: bigint; isShared: boolean }; + +type SimState = { + children: Map; + slots: Map; + created: Set; + networkToSlot: Map; + operatorBySlot: Map; + operatorToSlot: Map; + nextChildLocalIndex: Map; +}; + +function bigintCompare(a: bigint, b: bigint): number { + if (a < b) return -1; + if (a > b) return 1; + return 0; +} + +function shallowOptimizeOps(ops: UdOperation[]): UdOperation[] { + const out: UdOperation[] = []; + for (const op of ops) { + const last = out[out.length - 1]; + if (!last) { + out.push(op); + continue; + } + + if (last.kind === "setSize" && op.kind === "setSize" && last.index === op.index) { + out[out.length - 1] = op; + continue; + } + + if (last.kind === "setIsShared" && op.kind === "setIsShared" && last.index === op.index) { + out[out.length - 1] = op; + continue; + } + + if ( + last.kind === "swapSlots" && + op.kind === "swapSlots" && + last.index1 === op.index2 && + last.index2 === op.index1 + ) { + out.pop(); + continue; + } + + out.push(op); + } + + return out; +} + +function mergeOps(prevOps: UdOperation[], nextOps: UdOperation[]): UdOperation[] { + if (nextOps.length === 0) return prevOps; + const merged = prevOps.slice(); + for (const op of nextOps) { + if (op.kind === "createSlot" && op.slotId) { + const existingIndex = merged.findIndex((item) => item.kind === "createSlot" && item.slotId === op.slotId); + if (existingIndex !== -1) { + merged[existingIndex] = { ...merged[existingIndex], ...op }; + continue; + } + } + merged.push(op); + } + return merged; +} + +function cloneSimState(state: SimState): SimState { + return { + children: new Map([...state.children.entries()].map(([k, v]) => [k, v.slice()])), + slots: new Map([...state.slots.entries()].map(([k, v]) => [k, { ...v }])), + created: new Set(state.created), + networkToSlot: new Map(state.networkToSlot), + operatorBySlot: new Map(state.operatorBySlot), + operatorToSlot: new Map(state.operatorToSlot), + nextChildLocalIndex: new Map(state.nextChildLocalIndex), + }; +} + +function buildSimStateFromModel(model: UniversalDelegatorModel): SimState { + const state: SimState = { + children: new Map([[0n, []]]), + slots: new Map(), + created: new Set([0n]), + networkToSlot: new Map(), + operatorBySlot: new Map(), + operatorToSlot: new Map(), + nextChildLocalIndex: new Map(), + }; + + for (const group of model.groups) { + if (group.index === null) continue; + const groupIndex = group.index; + const groupSynced = group.state.synced; + const groupSize = parseUint(groupSynced?.size ?? group.state.draft.size) ?? 0n; + const groupIsShared = groupSynced?.isShared ?? group.state.draft.isShared; + + state.created.add(groupIndex); + state.slots.set(groupIndex, { size: groupSize, isShared: groupIsShared }); + state.children.get(0n)!.push(groupIndex); + if (!state.children.has(groupIndex)) state.children.set(groupIndex, []); + + for (const network of group.networks) { + if (network.index === null) continue; + const networkIndex = network.index; + const networkSynced = network.state.synced; + const networkSize = parseUint(networkSynced?.size ?? network.state.draft.size) ?? 0n; + + state.created.add(networkIndex); + state.slots.set(networkIndex, { size: networkSize, isShared: false }); + state.children.get(groupIndex)!.push(networkIndex); + if (!state.children.has(networkIndex)) state.children.set(networkIndex, []); + + const subnetworkRaw = (networkSynced?.subnetwork ?? network.state.draft.subnetwork).trim(); + const subnetworkParsed = subnetworkRaw === "" ? null : parseBytes32(subnetworkRaw); + if (subnetworkParsed) { + state.networkToSlot.set(subnetworkParsed.toLowerCase(), networkIndex); + } + + for (const operator of network.operators) { + if (operator.index === null) continue; + const operatorIndex = operator.index; + const operatorSynced = operator.state.synced; + const operatorSize = parseUint(operatorSynced?.size ?? operator.state.draft.size) ?? 0n; + + state.created.add(operatorIndex); + state.slots.set(operatorIndex, { size: operatorSize, isShared: false }); + state.children.get(networkIndex)!.push(operatorIndex); + if (!state.children.has(operatorIndex)) state.children.set(operatorIndex, []); + + const operatorRaw = (operatorSynced?.operator ?? operator.state.draft.operator).trim(); + if (operatorRaw !== "" && isAddress(operatorRaw)) { + const normalized = operatorRaw.toLowerCase(); + state.operatorBySlot.set(operatorIndex, operatorRaw as Address); + state.operatorToSlot.set(`${networkIndex.toString()}:${normalized}`, operatorIndex); + } + } + } + } + + for (const [parentIndex, children] of state.children.entries()) { + let maxChild = 0n; + for (const child of children) maxChild = bigintMax(maxChild, getChildIndex(child)); + state.nextChildLocalIndex.set(parentIndex, maxChild + 1n); + } + + if (!state.nextChildLocalIndex.has(0n)) state.nextChildLocalIndex.set(0n, 1n); + + return state; +} + +function simulateOpsFromState(initial: SimState, ops: UdOperation[]): SimState | null { + const state = cloneSimState(initial); + + for (const op of ops) { + if (op.kind === "createSlot") { + const local = state.nextChildLocalIndex.get(op.parentIndex) ?? 1n; + let index: bigint; + try { + index = createIndex(op.parentIndex, local); + } catch { + return null; + } + + state.nextChildLocalIndex.set(op.parentIndex, local + 1n); + state.created.add(index); + state.slots.set(index, { size: op.size, isShared: op.isShared }); + + if (!state.children.has(op.parentIndex)) state.children.set(op.parentIndex, []); + state.children.get(op.parentIndex)!.push(index); + if (!state.children.has(index)) state.children.set(index, []); + continue; + } + + if (op.kind === "setIsShared") { + const prev = state.slots.get(op.index) ?? { size: 0n, isShared: false }; + state.slots.set(op.index, { ...prev, isShared: op.isShared }); + continue; + } + + if (op.kind === "setSize") { + const prev = state.slots.get(op.index) ?? { size: 0n, isShared: false }; + state.slots.set(op.index, { ...prev, size: op.size }); + continue; + } + + if (op.kind === "swapSlots") { + const parent = getParentIndex(op.index1); + const list = state.children.get(parent); + if (!list) return null; + const i1 = list.indexOf(op.index1); + const i2 = list.indexOf(op.index2); + if (i1 === -1 || i2 === -1) return null; + [list[i1], list[i2]] = [list[i2]!, list[i1]!]; + continue; + } + + if (op.kind === "assignNetwork") { + state.networkToSlot.set(op.subnetwork.toLowerCase(), op.index); + continue; + } + + if (op.kind === "unassignNetwork") { + state.networkToSlot.set(op.subnetwork.toLowerCase(), 0n); + continue; + } + + if (op.kind === "assignOperator") { + const parentIndex = getParentIndex(op.index); + const key = `${parentIndex.toString()}:${op.operator.toLowerCase()}`; + state.operatorToSlot.set(key, op.index); + state.operatorBySlot.set(op.index, op.operator); + continue; + } + + const key = `${op.parentIndex.toString()}:${op.operator.toLowerCase()}`; + const currentIndex = state.operatorToSlot.get(key) ?? 0n; + if (currentIndex !== 0n) state.operatorBySlot.delete(currentIndex); + state.operatorToSlot.set(key, 0n); + } + + return state; +} + +function computeMinimalSwaps(initial: bigint[], target: bigint[]): UdOperation[] | null { + if (initial.length !== target.length) return null; + if (initial.length < 2) return []; + + const current = initial.slice(); + const pos = new Map(); + for (let i = 0; i < current.length; i += 1) pos.set(current[i], i); + + const swaps: UdOperation[] = []; + for (let i = 0; i < target.length; i += 1) { + const desired = target[i]; + const currentAt = current[i]; + if (currentAt === desired) continue; + + const j = pos.get(desired); + if (j === undefined) return null; + if (j < i) return null; + + swaps.push({ kind: "swapSlots", index1: currentAt, index2: desired }); + + current[i] = desired; + current[j] = currentAt; + pos.set(currentAt, j); + pos.set(desired, i); + } + + return swaps; +} + +function compileMinimalOpsFromInitialAndFinal(params: { initial: SimState; final: SimState }): UdOperation[] | null { + const initialExisting = new Set(params.initial.slots.keys()); + const createOps: UdOperation[] = []; + const swapOps: UdOperation[] = []; + const setOps: UdOperation[] = []; + const assignOps: UdOperation[] = []; + + function slotOrDefault(index: bigint): SimSlot { + return params.final.slots.get(index) ?? { size: 0n, isShared: false }; + } + + function buildCreates(parentIndex: bigint, depth: number) { + if (depth >= 3) return; + + const initialChildren = params.initial.children.get(parentIndex) ?? []; + const finalChildren = params.final.children.get(parentIndex) ?? []; + const finalSet = new Set(finalChildren); + + const existingChildrenInOrder = initialChildren.filter((child) => finalSet.has(child)); + const newChildren = finalChildren.filter((child) => !initialExisting.has(child)); + const newChildrenSorted = newChildren.slice().sort((a, b) => bigintCompare(getChildIndex(a), getChildIndex(b))); + + const creationOrder = [...existingChildrenInOrder, ...newChildrenSorted]; + for (const child of creationOrder) { + if (!initialExisting.has(child)) { + const slot = slotOrDefault(child); + createOps.push({ + kind: "createSlot", + parentIndex, + isShared: parentIndex === 0n ? slot.isShared : false, + size: slot.size, + }); + } + buildCreates(child, depth + 1); + } + } + + buildCreates(0n, 0); + + for (const [parentIndex, finalChildren] of params.final.children.entries()) { + const initialChildren = params.initial.children.get(parentIndex) ?? []; + const finalSet = new Set(finalChildren); + + const existingChildrenInOrder = initialChildren.filter((child) => finalSet.has(child)); + const newChildren = finalChildren.filter((child) => !initialExisting.has(child)); + const newChildrenSorted = newChildren.slice().sort((a, b) => bigintCompare(getChildIndex(a), getChildIndex(b))); + + const initialAfterCreate = [...existingChildrenInOrder, ...newChildrenSorted]; + const swaps = computeMinimalSwaps(initialAfterCreate, finalChildren); + if (swaps === null) return null; + swapOps.push(...swaps); + } + + for (const [index, finalSlot] of params.final.slots.entries()) { + if (!initialExisting.has(index)) continue; + const initialSlot = params.initial.slots.get(index) ?? { size: 0n, isShared: false }; + if (initialSlot.size !== finalSlot.size) { + setOps.push({ kind: "setSize", index, size: finalSlot.size }); + } + if (getParentIndex(index) === 0n && initialSlot.isShared !== finalSlot.isShared) { + setOps.push({ kind: "setIsShared", index, isShared: finalSlot.isShared }); + } + } + + const allSubnetworks = new Set(); + for (const key of params.initial.networkToSlot.keys()) allSubnetworks.add(key); + for (const key of params.final.networkToSlot.keys()) allSubnetworks.add(key); + const subnetworkKeys = [...allSubnetworks].sort((a, b) => (a < b ? -1 : a > b ? 1 : 0)); + for (const subnetwork of subnetworkKeys) { + const initialIndex = params.initial.networkToSlot.get(subnetwork) ?? 0n; + const finalIndex = params.final.networkToSlot.get(subnetwork) ?? 0n; + if (initialIndex === finalIndex) continue; + if (initialIndex !== 0n) assignOps.push({ kind: "unassignNetwork", subnetwork: subnetwork as Hex }); + if (finalIndex !== 0n) assignOps.push({ kind: "assignNetwork", index: finalIndex, subnetwork: subnetwork as Hex }); + } + + const allOperators = new Set(); + for (const key of params.initial.operatorToSlot.keys()) allOperators.add(key); + for (const key of params.final.operatorToSlot.keys()) allOperators.add(key); + const operatorKeys = [...allOperators].sort((a, b) => (a < b ? -1 : a > b ? 1 : 0)); + for (const key of operatorKeys) { + const initialIndex = params.initial.operatorToSlot.get(key) ?? 0n; + const finalIndex = params.final.operatorToSlot.get(key) ?? 0n; + if (initialIndex === finalIndex) continue; + + const [parentStr, operator] = key.split(":"); + if (!parentStr || !operator) continue; + let parentIndex: bigint; + try { + parentIndex = BigInt(parentStr); + } catch { + continue; + } + if (initialIndex !== 0n) { + assignOps.push({ kind: "unassignOperator", parentIndex, operator: operator as Address }); + } + if (finalIndex !== 0n) { + assignOps.push({ kind: "assignOperator", index: finalIndex, operator: operator as Address }); + } + } + + return [...createOps, ...swapOps, ...setOps, ...assignOps]; +} + +function compileOpsFromModels(params: { + baselineModel: UniversalDelegatorModel; + nextModel: UniversalDelegatorModel; +}): UdOperation[] | null { + const initial = buildSimStateFromModel(params.baselineModel); + const final = buildSimStateFromModel(params.nextModel); + return compileMinimalOpsFromInitialAndFinal({ initial, final }); +} + +type MulticallCandidate = { label: string; ops: UdOperation[] }; + +function opsKey(ops: UdOperation[]): string { + return JSON.stringify(ops.map(opToJson)); +} + +function buildMulticallCandidates(params: { + ops: UdOperation[]; + baselineModel: UniversalDelegatorModel; +}): MulticallCandidate[] { + const candidates: MulticallCandidate[] = []; + const seen = new Set(); + + function push(label: string, list: UdOperation[]) { + const key = opsKey(list); + if (seen.has(key)) return; + seen.add(key); + candidates.push({ label, ops: list }); + } + + if (params.ops.length === 0) return candidates; + + const initial = buildSimStateFromModel(params.baselineModel); + const final = simulateOpsFromState(initial, params.ops); + if (final) { + const compiled = compileMinimalOpsFromInitialAndFinal({ initial, final }); + if (compiled) { + push("optimized", compiled); + } + } + + push("shallow", shallowOptimizeOps(params.ops)); + push("raw", params.ops); + + return candidates; +} + +function candidatePriority(label: string): number { + if (label === "optimized") return 0; + if (label === "shallow") return 1; + return 2; +} + +function orderMulticallCandidates(candidates: MulticallCandidate[]): MulticallCandidate[] { + return candidates + .slice() + .sort((a, b) => a.ops.length - b.ops.length || candidatePriority(a.label) - candidatePriority(b.label)); +} + +function encodeOpsToCalls(ops: UdOperation[]): Hex[] { + const calls: Hex[] = []; + for (const op of ops) { + if (op.kind === "createSlot") { + calls.push( + encodeFunctionData({ + abi: universalDelegatorAbi, + functionName: "createSlot", + args: [op.parentIndex, op.isShared, op.size], + }), + ); + } else if (op.kind === "setIsShared") { + calls.push( + encodeFunctionData({ + abi: universalDelegatorAbi, + functionName: "setIsShared", + args: [op.index, op.isShared], + }), + ); + } else if (op.kind === "setSize") { + calls.push( + encodeFunctionData({ + abi: universalDelegatorAbi, + functionName: "setSize", + args: [op.index, op.size], + }), + ); + } else if (op.kind === "swapSlots") { + calls.push( + encodeFunctionData({ + abi: universalDelegatorAbi, + functionName: "swapSlots", + args: [op.index1, op.index2], + }), + ); + } else if (op.kind === "assignNetwork") { + calls.push( + encodeFunctionData({ + abi: universalDelegatorAbi, + functionName: "assignNetwork", + args: [op.index, op.subnetwork], + }), + ); + } else if (op.kind === "unassignNetwork") { + calls.push( + encodeFunctionData({ + abi: universalDelegatorAbi, + functionName: "unassignNetwork", + args: [op.subnetwork], + }), + ); + } else if (op.kind === "assignOperator") { + calls.push( + encodeFunctionData({ + abi: universalDelegatorAbi, + functionName: "assignOperator", + args: [op.index, op.operator], + }), + ); + } else { + calls.push( + encodeFunctionData({ + abi: universalDelegatorAbi, + functionName: "unassignOperator", + args: [op.parentIndex, op.operator], + }), + ); + } + } + return calls; +} + +function formatViemError(error: unknown): string { + if (error instanceof ContractFunctionRevertedError) { + const data = error.data; + if (data?.errorName) { + if (data.args && data.args.length > 0) { + const args = data.args.map((arg) => String(arg)).join(", "); + return `${data.errorName}(${args})`; + } + return data.errorName; + } + if (error.reason) return error.reason; + } + if (error instanceof BaseError) return error.shortMessage ?? error.message; + if (error instanceof Error) return error.message; + return "Unknown error"; +} + +function extractRevertName(error: unknown): string | null { + if (error instanceof ContractFunctionRevertedError) return error.data?.errorName ?? null; + if (error instanceof BaseError) { + const nested = error.walk((err) => err instanceof ContractFunctionRevertedError); + if (nested instanceof ContractFunctionRevertedError) return nested.data?.errorName ?? null; + } + return null; +} + +type CandidateSimulationResult = { + candidate: MulticallCandidate; + status: "success" | "failure"; + error?: unknown; +}; + +function computeSimulatedAllocationsFromState(state: SimState, rootBalance: bigint): Map { + const allocated = new Map(); + allocated.set(0n, rootBalance); + + const walk = (parentIndex: bigint) => { + const children = state.children.get(parentIndex) ?? []; + const parentAllocated = allocated.get(parentIndex) ?? 0n; + const parentSlot = state.slots.get(parentIndex); + const parentIsShared = parentIndex === 0n ? false : (parentSlot?.isShared ?? false); + + let prevSum = 0n; + for (const child of children) { + const childSlot = state.slots.get(child) ?? { size: 0n, isShared: false }; + const childAllocated = parentIsShared + ? bigintMin(parentAllocated, childSlot.size) + : bigintMin(saturatingSub(parentAllocated, prevSum), childSlot.size); + allocated.set(child, childAllocated); + prevSum += childSlot.size; + walk(child); + } + }; + + walk(0n); + return allocated; +} + +function describeNotEnoughAvailable(params: { + ops: UdOperation[]; + failureIndex: number; + baselineModel: UniversalDelegatorModel; + rootBalance: bigint | null; +}): string | null { + const failing = params.ops[params.failureIndex]; + if (!failing || failing.kind !== "setSize") return null; + + const initial = buildSimStateFromModel(params.baselineModel); + const before = simulateOpsFromState(initial, params.ops.slice(0, params.failureIndex)); + if (!before) return null; + + const prevSize = before.slots.get(failing.index)?.size ?? 0n; + if (failing.size <= prevSize) return null; + const increase = failing.size - prevSize; + + const parentIndex = getParentIndex(failing.index); + const parentDepth = getDepth(parentIndex); + const childDepth = getDepth(failing.index); + const parentLabel = + parentDepth === 0 + ? "root" + : parentDepth === 1 + ? `Group #${getChildIndex(parentIndex)}` + : `Network #${getChildIndex(parentIndex)}`; + const childLabel = childDepth === 1 ? "Group" : childDepth === 2 ? "Network" : "Operator"; + + const children = before.children.get(parentIndex) ?? []; + let childrenSize = 0n; + for (const child of children) { + childrenSize += before.slots.get(child)?.size ?? 0n; + } + + let available: bigint | null = null; + if (parentIndex === 0n) { + available = params.rootBalance; + } else if (params.rootBalance !== null) { + const allocated = computeSimulatedAllocationsFromState(before, params.rootBalance); + available = allocated.get(parentIndex) ?? null; + } + if (available === null) { + available = before.slots.get(parentIndex)?.size ?? null; + } + if (available === null) return null; + + const unallocated = saturatingSub(available, childrenSize); + if (increase <= unallocated) return null; + return `${childLabel} size increase by ${increase.toString()} in ${parentLabel} exceeds available ${unallocated.toString()}.`; +} + +async function simulateMulticallCandidates(params: { + publicClient: PublicClient; + delegatorAddress: Address; + account: Address; + candidates: MulticallCandidate[]; +}): Promise { + if (params.candidates.length === 0) return []; + const calls = params.candidates.map((candidate) => ({ + to: params.delegatorAddress, + abi: universalDelegatorAbi, + functionName: "multicall", + args: [encodeOpsToCalls(candidate.ops)], + })); + const { results } = await params.publicClient.simulateCalls({ + account: params.account, + calls, + }); + return results.map((result, index) => ({ + candidate: params.candidates[index]!, + status: result.status, + error: result.status === "failure" ? result.error : undefined, + })); +} + +async function simulateMulticall(params: { + publicClient: PublicClient; + delegatorAddress: Address; + account: Address; + calls: Hex[]; +}): Promise { + if (params.calls.length === 0) return; + await params.publicClient.simulateContract({ + address: params.delegatorAddress, + abi: universalDelegatorAbi, + functionName: "multicall", + args: [params.calls], + account: params.account, + }); +} + +async function findFailingOp(params: { + publicClient: PublicClient; + delegatorAddress: Address; + account: Address; + ops: UdOperation[]; +}): Promise<{ index: number; error: unknown } | null> { + if (params.ops.length === 0) return null; + const calls = encodeOpsToCalls(params.ops); + if (calls.length === 0) return null; + + let low = 0; + let high = calls.length - 1; + let failure: { index: number; error: unknown } | null = null; + + while (low <= high) { + const mid = Math.floor((low + high) / 2); + try { + await simulateMulticall({ + publicClient: params.publicClient, + delegatorAddress: params.delegatorAddress, + account: params.account, + calls: calls.slice(0, mid + 1), + }); + low = mid + 1; + } catch (error) { + failure = { index: mid, error }; + high = mid - 1; + } + } + + return failure; +} + +function opsBaselineModel(params: { + model: UniversalDelegatorModel; + ops: UdOperation[]; + history: Array<{ model: UniversalDelegatorModel; ops: UdOperation[] }>; +}): UniversalDelegatorModel { + if (params.ops.length === 0) return params.model; + for (let i = params.history.length - 1; i >= 0; i -= 1) { + const snapshot = params.history[i]; + if (snapshot && snapshot.ops.length === 0) return snapshot.model; + } + return params.history[0]?.model ?? params.model; +} + +export function UniversalDelegatorConfigurator() { + const { login, logout, authenticated } = usePrivy(); + const { address: accountAddress, isConnected, chain } = useAccount(); + const publicClient = usePublicClient(); + + const { writeContractAsync, data: txHash, isPending, error } = useWriteContract(); + const { isLoading: isConfirming, isSuccess: isConfirmed } = useWaitForTransactionReceipt({ + hash: txHash, + query: { enabled: Boolean(txHash) }, + }); + const handledTxHashRef = useRef(null); + + const nextId = useRef(1); + const newId = (prefix: string) => `${prefix}-${nextId.current++}`; + + const [delegatorAddress, setDelegatorAddress] = useState(""); + const [model, setModel] = useState({ groups: [] }); + const [ops, setOps] = useState([]); + const [history, setHistory] = useState>([]); + const [zoom, setZoom] = useState({ kind: "all" }); + const [hoveredGroupId, setHoveredGroupId] = useState(null); + const [groupConstructor, setGroupConstructor] = useState("shared-multi"); + const [groupNetworksInput, setGroupNetworksInput] = useState("2"); + const [groupOperatorsInput, setGroupOperatorsInput] = useState("2"); + const [swapCandidateId, setSwapCandidateId] = useState(""); + const [isReconstructing, setIsReconstructing] = useState(false); + const [reconstructError, setReconstructError] = useState(null); + const [toastMessage, setToastMessage] = useState(null); + const [selectedOps, setSelectedOps] = useState([]); + const [selectedCandidateLabel, setSelectedCandidateLabel] = useState("optimized"); + const [multicallWarning, setMulticallWarning] = useState(null); + const [multicallError, setMulticallError] = useState(null); + const [multicallErrorOp, setMulticallErrorOp] = useState<{ index: number; op: UdOperation } | null>(null); + const [isValidatingMulticall, setIsValidatingMulticall] = useState(false); + const [reconstructNonce, setReconstructNonce] = useState(0); + const toastTimeoutRef = useRef | null>(null); + const baselineModelRef = useRef(null); + const rootBalanceRef = useRef(null); + + const baselineModel = useMemo(() => opsBaselineModel({ model, ops, history }), [history, model, ops]); + baselineModelRef.current = baselineModel; + + const multicallCandidates = useMemo(() => buildMulticallCandidates({ ops, baselineModel }), [baselineModel, ops]); + const orderedMulticallCandidates = useMemo( + () => orderMulticallCandidates(multicallCandidates), + [multicallCandidates], + ); + + const flashToast = useCallback((message: string) => { + setToastMessage(message); + if (toastTimeoutRef.current) clearTimeout(toastTimeoutRef.current); + toastTimeoutRef.current = setTimeout(() => setToastMessage(null), 1500); + }, []); + + useEffect( + () => () => { + if (toastTimeoutRef.current) clearTimeout(toastTimeoutRef.current); + }, + [], + ); + + useEffect(() => { + if (!isConfirmed || !txHash) return; + if (handledTxHashRef.current === txHash) return; + handledTxHashRef.current = txHash; + + setOps([]); + setHistory([]); + setSelectedOps([]); + setSelectedCandidateLabel("optimized"); + setMulticallWarning(null); + setMulticallError(null); + setMulticallErrorOp(null); + setIsValidatingMulticall(false); + }, [isConfirmed, txHash]); + + const copyIndexToClipboard = useCallback( + (index: bigint) => { + const text = formatIndex(index); + void navigator.clipboard.writeText(text).catch(() => {}); + flashToast("Index copied!"); + }, + [flashToast], + ); + + useEffect(() => { + let cancelled = false; + + const validate = async () => { + setMulticallWarning(null); + setMulticallError(null); + setMulticallErrorOp(null); + setIsValidatingMulticall(false); + + if (orderedMulticallCandidates.length === 0) { + setSelectedOps([]); + setSelectedCandidateLabel("optimized"); + return; + } + + const primary = orderedMulticallCandidates[0]; + setSelectedOps(primary.ops); + setSelectedCandidateLabel(primary.label); + + if (!publicClient || !isAddress(delegatorAddress)) { + return; + } + + if (!accountAddress || !isAddress(accountAddress)) { + if (primary.ops.length > 0) { + setMulticallWarning("Connect wallet to validate multicall execution."); + } + return; + } + + setIsValidatingMulticall(true); + let lastError: unknown = null; + + try { + const applyCandidate = (candidate: MulticallCandidate) => { + setSelectedOps(candidate.ops); + setSelectedCandidateLabel(candidate.label); + setMulticallWarning( + candidate.label === primary.label + ? null + : `Using fallback strategy: ${candidate.label}. Optimal strategy reverted during simulation.`, + ); + setMulticallError(null); + setMulticallErrorOp(null); + }; + + let candidateResults: CandidateSimulationResult[] | null = null; + try { + candidateResults = await simulateMulticallCandidates({ + publicClient, + delegatorAddress: delegatorAddress as Address, + account: accountAddress as Address, + candidates: orderedMulticallCandidates, + }); + } catch (error) { + lastError = error; + } + + if (candidateResults) { + const success = candidateResults.find((result) => result.status === "success"); + if (success) { + if (cancelled) return; + applyCandidate(success.candidate); + return; + } + const primaryResult = candidateResults[0]; + if (primaryResult?.status === "failure") { + lastError = primaryResult.error; + } else { + lastError = candidateResults.find((result) => result.status === "failure")?.error ?? lastError; + } + } else { + for (const candidate of orderedMulticallCandidates) { + const calls = encodeOpsToCalls(candidate.ops); + if (calls.length === 0) { + if (cancelled) return; + applyCandidate(candidate); + return; + } + + try { + await simulateMulticall({ + publicClient, + delegatorAddress: delegatorAddress as Address, + account: accountAddress as Address, + calls, + }); + if (cancelled) return; + applyCandidate(candidate); + return; + } catch (error) { + lastError = error; + } + } + } + + const failure = await findFailingOp({ + publicClient, + delegatorAddress: delegatorAddress as Address, + account: accountAddress as Address, + ops: primary.ops, + }); + if (cancelled) return; + + const baseError = failure?.error ?? lastError; + const errorName = extractRevertName(baseError); + const baselineSnapshot = baselineModelRef.current; + const rootBalanceSnapshot = rootBalanceRef.current; + const detailed = + failure && baselineSnapshot + ? describeNotEnoughAvailable({ + ops: primary.ops, + failureIndex: failure.index, + baselineModel: baselineSnapshot, + rootBalance: rootBalanceSnapshot, + }) + : null; + const fallbackReason = formatViemError(baseError); + const useDetailed = + Boolean(detailed) && + (errorName === "NotEnoughAvailable" || (errorName === null && fallbackReason.includes("multicall"))); + const reason = useDetailed ? detailed! : fallbackReason; + if (failure && primary.ops[failure.index]) { + setMulticallErrorOp({ index: failure.index, op: primary.ops[failure.index]! }); + setMulticallError( + `Op #${failure.index + 1} ${formatOp(primary.ops[failure.index]!)} would revert: ${reason}`, + ); + } else { + setMulticallError(`Multicall would revert: ${reason}`); + } + } finally { + if (!cancelled) setIsValidatingMulticall(false); + } + }; + + void validate(); + return () => { + cancelled = true; + }; + }, [accountAddress, delegatorAddress, orderedMulticallCandidates, publicClient]); + + const balanceIndices = useMemo(() => [0n], []); + + const canReadBalances = isAddress(delegatorAddress) && balanceIndices.length > 0; + const balanceReads = useMemo(() => { + if (!canReadBalances) return []; + const address = delegatorAddress as Address; + return balanceIndices.map((index) => ({ + address, + abi: universalDelegatorAbi, + functionName: "getBalance" as const, + args: [index] as const, + })); + }, [balanceIndices, canReadBalances, delegatorAddress]); + + const { data: balancesData, isLoading: balancesLoading } = useReadContracts({ + allowFailure: true, + contracts: balanceReads, + query: { enabled: canReadBalances, refetchInterval: 5000 }, + }); + + const balancesByIndex = useMemo(() => { + const map = new Map(); + if (!balancesData) return map; + for (let i = 0; i < balancesData.length; i += 1) { + const item = balancesData[i]; + if (!item) continue; + if ("result" in item && item.result !== undefined) { + map.set(balanceIndices[i]!.toString(), item.result as bigint); + } + } + return map; + }, [balanceIndices, balancesData]); + + const rootBalance = balancesByIndex.get("0") ?? null; + rootBalanceRef.current = rootBalance; + const slotIdToIndex = useMemo(() => computeSlotIdToIndex(model), [model]); + const baselineSlotIdToIndex = useMemo(() => computeSlotIdToIndex(baselineModel), [baselineModel]); + const allocationIndices = useMemo(() => { + const seen = new Set(); + const out: bigint[] = []; + for (const index of slotIdToIndex.values()) { + if (index === 0n) continue; + const key = index.toString(); + if (seen.has(key)) continue; + seen.add(key); + out.push(index); + } + out.sort(bigintCompare); + return out; + }, [slotIdToIndex]); + + const canReadOnchainAllocations = isAddress(delegatorAddress) && allocationIndices.length > 0; + const allocationReads = useMemo(() => { + if (!canReadOnchainAllocations) return []; + const address = delegatorAddress as Address; + return allocationIndices.map((index) => ({ + address, + abi: universalDelegatorAbi, + functionName: "getAllocated" as const, + args: [index] as const, + })); + }, [allocationIndices, canReadOnchainAllocations, delegatorAddress]); + + const { data: allocatedData, isLoading: allocatedLoading } = useReadContracts({ + allowFailure: true, + contracts: allocationReads, + query: { enabled: canReadOnchainAllocations, refetchInterval: 5000 }, + }); + + const onchainAllocationsByIndex = useMemo(() => { + const map = new Map(); + if (!allocatedData) return map; + for (let i = 0; i < allocatedData.length; i += 1) { + const item = allocatedData[i]; + if (!item) continue; + if ("result" in item && item.result !== undefined) { + const index = allocationIndices[i]; + if (index === undefined) continue; + map.set(index.toString(), item.result as bigint); + } + } + return map; + }, [allocatedData, allocationIndices]); + + const availableIndices = useMemo(() => [0n, ...allocationIndices], [allocationIndices]); + const canReadAvailable = isAddress(delegatorAddress) && availableIndices.length > 0; + const availableReads = useMemo< + Array<{ + address: Address; + abi: typeof universalDelegatorAbi; + functionName: "getAvailable"; + args: readonly [bigint]; + }> + >(() => { + if (!canReadAvailable) return []; + const address = delegatorAddress as Address; + return availableIndices.map((index) => ({ + address, + abi: universalDelegatorAbi, + functionName: "getAvailable" as const, + args: [index] as const, + })); + }, [availableIndices, canReadAvailable, delegatorAddress]); + + const { data: availableData, isLoading: availableLoading } = useReadContracts({ + allowFailure: true, + contracts: availableReads, + query: { enabled: canReadAvailable, refetchInterval: 5000 }, + }) as { + data?: Array<{ result?: bigint } | { error?: BaseError } | null>; + isLoading: boolean; + }; + + const onchainPendingByIndex = useMemo(() => { + const map = new Map(); + if (!availableData) return map; + for (let i = 0; i < availableData.length; i += 1) { + const item = availableData[i]; + if (!item) continue; + if ("result" in item && item.result !== undefined) { + const index = availableIndices[i]; + if (index === undefined) continue; + const available = item.result as bigint; + const balance = index === 0n ? (rootBalance ?? 0n) : (onchainAllocationsByIndex.get(index.toString()) ?? 0n); + map.set(index.toString(), saturatingSub(balance, available)); + } + } + return map; + }, [availableData, availableIndices, onchainAllocationsByIndex, rootBalance]); + + const baselineAllocationsByIndex = useMemo( + () => computeSimulatedAllocations(baselineModel, baselineSlotIdToIndex, rootBalance), + [baselineModel, baselineSlotIdToIndex, rootBalance], + ); + const candidateOpsKeys = useMemo( + () => new Set(orderedMulticallCandidates.map((candidate) => opsKey(candidate.ops))), + [orderedMulticallCandidates], + ); + const pendingOpsForSimulation = useMemo(() => { + if (orderedMulticallCandidates.length === 0) return []; + if (selectedOps.length > 0 && candidateOpsKeys.has(opsKey(selectedOps))) return selectedOps; + return orderedMulticallCandidates[0]?.ops ?? []; + }, [candidateOpsKeys, orderedMulticallCandidates, selectedOps]); + const simulatedPendingByIndexOverride = useMemo( + () => + computePendingByIndexFromOps({ + baselineModel, + ops: pendingOpsForSimulation, + rootActiveStake: rootBalance, + baselinePendingByIndex: onchainPendingByIndex, + }), + [baselineModel, onchainPendingByIndex, pendingOpsForSimulation, rootBalance], + ); + const simulatedAllocations = useMemo( + () => + computeSimulatedAllocationsWithPending({ + model, + slotIdToIndex, + baselineSlotIdToIndex, + baselineAllocationsByIndex, + rootActiveStake: rootBalance, + pendingByIndexOverride: simulatedPendingByIndexOverride, + }), + [ + baselineAllocationsByIndex, + baselineSlotIdToIndex, + model, + rootBalance, + simulatedPendingByIndexOverride, + slotIdToIndex, + ], + ); + const simulatedAllocationsByIndex = simulatedAllocations.allocatedByIndex; + const simulatedPendingByIndex = simulatedAllocations.pendingByIndex; + const visibleGroups = useMemo(() => { + if (zoom.kind === "all") return model.groups; + const group = model.groups.find((g) => g.id === zoom.groupId); + if (!group) return []; + if (zoom.kind === "group") return [group]; + const network = group.networks.find((n) => n.id === zoom.networkId); + if (!network) return []; + return [{ ...group, networks: [network] }]; + }, [model.groups, zoom]); + + useEffect(() => { + if (zoom.kind === "all") return; + const group = model.groups.find((g) => g.id === zoom.groupId); + if (!group) { + setZoom({ kind: "all" }); + return; + } + if (zoom.kind === "network") { + const network = group.networks.find((n) => n.id === zoom.networkId); + if (!network) setZoom({ kind: "group", groupId: group.id }); + } + }, [model.groups, zoom]); + const shouldUseOnchainAllocations = + isAddress(delegatorAddress) && (pendingOpsForSimulation.length === 0 || orderedMulticallCandidates.length === 0); + + const allocationsByIndex = shouldUseOnchainAllocations ? onchainAllocationsByIndex : simulatedAllocationsByIndex; + const pendingByIndex = shouldUseOnchainAllocations ? onchainPendingByIndex : simulatedPendingByIndex; + const hasRootBalance = rootBalance !== null; + const allocationsLoading = shouldUseOnchainAllocations + ? allocatedLoading + : canReadBalances && balancesLoading && rootBalance === null; + const pendingLoading = shouldUseOnchainAllocations ? availableLoading || allocatedLoading : false; + + const encodedCalls = useMemo(() => encodeOpsToCalls(selectedOps), [selectedOps]); + + const multicallCalldata = useMemo(() => { + if (encodedCalls.length === 0) return null; + return encodeFunctionData({ + abi: universalDelegatorAbi, + functionName: "multicall", + args: [encodedCalls], + }); + }, [encodedCalls]); + + function pushHistorySnapshot() { + setHistory((prev) => [...prev, { model: cloneModel(model), ops: cloneOps(ops) }]); + } + + const undo = useCallback(() => { + setHistory((prev) => { + const last = prev[prev.length - 1]; + if (!last) return prev; + setModel(last.model); + setOps(last.ops); + return prev.slice(0, -1); + }); + }, []); + + const resetToOnchain = useCallback(() => { + setOps([]); + setHistory([]); + setSelectedOps([]); + setSelectedCandidateLabel("optimized"); + setMulticallWarning(null); + setMulticallError(null); + setMulticallErrorOp(null); + setIsValidatingMulticall(false); + setReconstructNonce((prev) => prev + 1); + }, []); + + useEffect(() => { + const onKeyDown = (e: KeyboardEvent) => { + if (e.defaultPrevented) return; + if (!(e.ctrlKey || e.metaKey)) return; + if (e.shiftKey) return; + if (e.key.toLowerCase() !== "z") return; + + const target = e.target as HTMLElement | null; + const tag = target?.tagName?.toLowerCase(); + const isTextInput = + tag === "input" || + tag === "textarea" || + tag === "select" || + Boolean(target && "isContentEditable" in target && (target as HTMLElement).isContentEditable); + if (isTextInput) return; + + e.preventDefault(); + undo(); + }; + + window.addEventListener("keydown", onKeyDown); + return () => window.removeEventListener("keydown", onKeyDown); + }, [undo]); + + useEffect(() => { + const trimmed = delegatorAddress.trim(); + if (!publicClient) return; + if (!isAddress(trimmed)) { + setIsReconstructing(false); + setReconstructError(null); + return; + } + + let cancelled = false; + setIsReconstructing(true); + setReconstructError(null); + (async () => { + try { + const onchainModel = await reconstructModelFromChain({ + delegatorAddress: trimmed as Address, + publicClient, + }); + if (cancelled) return; + setModel(onchainModel); + setOps([]); + setHistory([]); + } catch (e) { + if (cancelled) return; + setReconstructError(e instanceof Error ? e.message : String(e)); + } finally { + if (!cancelled) setIsReconstructing(false); + } + })(); + + return () => { + cancelled = true; + }; + }, [delegatorAddress, publicClient, reconstructNonce]); + + function addDraftGroup() { + pushHistorySnapshot(); + const group: GroupSlot = { + id: newId("group"), + index: null, + state: { draft: { size: "", isShared: false }, synced: null }, + networks: [], + }; + setModel((prev) => ({ ...prev, groups: [...prev.groups, group] })); + } + + function addGroupFromTemplate() { + if (!addGroupValid) return; + pushHistorySnapshot(); + const makeOperator = (): OperatorSlot => ({ + id: newId("operator"), + index: null, + state: { draft: { size: "", operator: "" }, synced: null }, + }); + const makeNetwork = (operatorCount: number): NetworkSlot => ({ + id: newId("network"), + index: null, + state: { draft: { size: "", subnetwork: "" }, synced: null }, + operators: Array.from({ length: operatorCount }, makeOperator), + }); + + const isShared = groupConstructor === "shared-multi" || groupConstructor === "shared-single"; + let networks: NetworkSlot[] = []; + if (groupConstructor === "shared-multi") { + const netCount = groupNetworksCount ?? 0; + const opCount = groupOperatorsCount ?? 0; + networks = Array.from({ length: netCount }, () => makeNetwork(opCount)); + } else if (groupConstructor === "shared-single") { + const netCount = groupNetworksCount ?? 0; + networks = Array.from({ length: netCount }, () => makeNetwork(1)); + } else if (groupConstructor === "single-multi") { + const opCount = groupOperatorsCount ?? 0; + networks = [makeNetwork(opCount)]; + } else { + networks = [makeNetwork(1)]; + } + + const group: GroupSlot = { + id: newId("group"), + index: null, + state: { draft: { size: "", isShared }, synced: null }, + networks, + }; + setModel((prev) => ({ ...prev, groups: [...prev.groups, group] })); + } + + function swapNeighborSlots() { + const candidate = swapCandidates.find((item) => item.id === swapCandidateId); + if (!candidate) return; + pushHistorySnapshot(); + setModel((prev) => { + let didSwap = false; + let nextModel: UniversalDelegatorModel = prev; + + if (zoom.kind === "all") { + const leftIndex = prev.groups.findIndex((g) => g.id === candidate.leftId); + const rightIndex = prev.groups.findIndex((g) => g.id === candidate.rightId); + if (leftIndex === -1 || rightIndex === -1) return prev; + const groups = prev.groups.slice(); + [groups[leftIndex], groups[rightIndex]] = [groups[rightIndex]!, groups[leftIndex]!]; + nextModel = { ...prev, groups }; + didSwap = true; + } else if (zoom.kind === "group") { + const groups = prev.groups.map((g) => { + if (g.id !== zoom.groupId) return g; + const leftIndex = g.networks.findIndex((n) => n.id === candidate.leftId); + const rightIndex = g.networks.findIndex((n) => n.id === candidate.rightId); + if (leftIndex === -1 || rightIndex === -1) return g; + const networks = g.networks.slice(); + [networks[leftIndex], networks[rightIndex]] = [networks[rightIndex]!, networks[leftIndex]!]; + didSwap = true; + return { ...g, networks }; + }); + nextModel = didSwap ? { ...prev, groups } : prev; + } else { + const groups = prev.groups.map((g) => { + if (g.id !== zoom.groupId) return g; + return { + ...g, + networks: g.networks.map((n) => { + if (n.id !== zoom.networkId) return n; + const leftIndex = n.operators.findIndex((o) => o.id === candidate.leftId); + const rightIndex = n.operators.findIndex((o) => o.id === candidate.rightId); + if (leftIndex === -1 || rightIndex === -1) return n; + const operators = n.operators.slice(); + [operators[leftIndex], operators[rightIndex]] = [operators[rightIndex]!, operators[leftIndex]!]; + didSwap = true; + return { ...n, operators }; + }), + }; + }); + nextModel = didSwap ? { ...prev, groups } : prev; + } + + if (!didSwap) return prev; + + setOps((prevOps) => { + const compiled = compileOpsFromModels({ baselineModel, nextModel }); + return compiled ?? prevOps; + }); + return nextModel; + }); + } + + function updateGroupDraft(groupId: string, patch: Partial) { + pushHistorySnapshot(); + setModel((prev) => { + const updated: UniversalDelegatorModel = { + ...prev, + groups: prev.groups.map((g) => + g.id === groupId ? { ...g, state: { ...g.state, draft: { ...g.state.draft, ...patch } } } : g, + ), + }; + const auto = autoSyncAll(updated); + setOps((prevOps) => { + const compiled = compileOpsFromModels({ baselineModel, nextModel: auto.model }); + if (compiled) return compiled; + if (auto.ops.length === 0) return prevOps; + return shallowOptimizeOps(mergeOps(prevOps, auto.ops)); + }); + return auto.model; + }); + } + + function addDraftNetwork(groupId: string) { + pushHistorySnapshot(); + const group = model.groups.find((g) => g.id === groupId); + if (!group) return; + + const network: NetworkSlot = { + id: newId("network"), + index: null, + state: { draft: { size: "", subnetwork: "" }, synced: null }, + operators: [], + }; + + setModel((prev) => ({ + ...prev, + groups: prev.groups.map((g) => (g.id === groupId ? { ...g, networks: [...g.networks, network] } : g)), + })); + } + + function updateNetworkDraft(groupId: string, networkId: string, patch: Partial) { + pushHistorySnapshot(); + setModel((prev) => { + const updated: UniversalDelegatorModel = { + ...prev, + groups: prev.groups.map((g) => { + if (g.id !== groupId) return g; + return { + ...g, + networks: g.networks.map((n) => + n.id === networkId ? { ...n, state: { ...n.state, draft: { ...n.state.draft, ...patch } } } : n, + ), + }; + }), + }; + const auto = autoSyncAll(updated); + setOps((prevOps) => { + const compiled = compileOpsFromModels({ baselineModel, nextModel: auto.model }); + if (compiled) return compiled; + if (auto.ops.length === 0) return prevOps; + return shallowOptimizeOps(mergeOps(prevOps, auto.ops)); + }); + return auto.model; + }); + } + + function addDraftOperator(groupId: string, networkId: string) { + const group = model.groups.find((g) => g.id === groupId); + const network = group?.networks.find((n) => n.id === networkId); + if (!network) return; + + pushHistorySnapshot(); + + const slot: OperatorSlot = { + id: newId("operator"), + index: null, + state: { draft: { size: "", operator: "" }, synced: null }, + }; + + setModel((prev) => ({ + ...prev, + groups: prev.groups.map((g) => { + if (g.id !== groupId) return g; + return { + ...g, + networks: g.networks.map((n) => (n.id === networkId ? { ...n, operators: [...n.operators, slot] } : n)), + }; + }), + })); + } + + function updateOperatorDraft(groupId: string, networkId: string, operatorId: string, patch: Partial) { + pushHistorySnapshot(); + setModel((prev) => { + const updated: UniversalDelegatorModel = { + ...prev, + groups: prev.groups.map((g) => { + if (g.id !== groupId) return g; + return { + ...g, + networks: g.networks.map((n) => { + if (n.id !== networkId) return n; + return { + ...n, + operators: n.operators.map((o) => + o.id === operatorId ? { ...o, state: { ...o.state, draft: { ...o.state.draft, ...patch } } } : o, + ), + }; + }), + }; + }), + }; + const auto = autoSyncAll(updated); + setOps((prevOps) => { + const compiled = compileOpsFromModels({ baselineModel, nextModel: auto.model }); + if (compiled) return compiled; + if (auto.ops.length === 0) return prevOps; + return shallowOptimizeOps(mergeOps(prevOps, auto.ops)); + }); + return auto.model; + }); + } + + async function executeMulticall() { + if (!isConnected || !accountAddress) return; + if (!isAddress(delegatorAddress)) return; + if (encodedCalls.length === 0) return; + + try { + await writeContractAsync({ + abi: universalDelegatorAbi, + address: delegatorAddress as Address, + functionName: "multicall", + args: [encodedCalls], + }); + } catch { + // error state handled by wagmi hook + } + } + + const primaryCandidateLabel = orderedMulticallCandidates[0]?.label ?? "optimized"; + + const canExecute = + isConnected && + isAddress(delegatorAddress) && + encodedCalls.length > 0 && + !isPending && + !isValidatingMulticall && + !multicallError; + + const groupSizeValues = visibleGroups.map((group) => effectiveSize(group.state)); + const groupTotalSize = sumBigints(groupSizeValues); + const walletConnected = Boolean(authenticated && isConnected && accountAddress); + const shortAccountAddress = accountAddress ? formatShortAddress(accountAddress) : ""; + const chainLabel = chain?.name ?? "Unknown chain"; + const walletStatusLabel = walletConnected ? "Wallet connected" : "Wallet disconnected"; + const delegatorTrimmed = delegatorAddress.trim(); + const isDelegatorInvalid = delegatorTrimmed.length > 0 && !isAddress(delegatorTrimmed); + const zoomCrumbs = useMemo(() => { + const crumbs: Array< + | { kind: "groups"; label: string } + | { kind: "group"; label: string; groupId: string } + | { kind: "network"; label: string; groupId: string; networkId: string } + > = [{ kind: "groups", label: "Groups" }]; + + if (zoom.kind === "all") return crumbs; + const group = model.groups.find((g) => g.id === zoom.groupId); + if (!group) return crumbs; + + const groupIndex = slotIdToIndex.get(group.id); + const groupLabel = groupIndex !== undefined ? `Group ${getChildIndex(groupIndex)}` : "Group"; + crumbs.push({ kind: "group", label: groupLabel, groupId: group.id }); + + if (zoom.kind !== "network") return crumbs; + const network = group.networks.find((n) => n.id === zoom.networkId); + if (!network) return crumbs; + const networkIndex = slotIdToIndex.get(network.id); + const networkLabel = networkIndex !== undefined ? `Network ${getChildIndex(networkIndex)}` : "Network"; + crumbs.push({ kind: "network", label: networkLabel, groupId: group.id, networkId: network.id }); + return crumbs; + }, [model.groups, slotIdToIndex, zoom]); + const hoverActionClass = + "transition-colors hover:bg-primary/10 hover:border-primary/30 hover:text-base-content hover:shadow-sm " + + "focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary"; + const groupNetworksCount = parsePositiveInt(groupNetworksInput); + const groupOperatorsCount = parsePositiveInt(groupOperatorsInput); + const needsNetworks = groupConstructor === "shared-multi" || groupConstructor === "shared-single"; + const needsOperators = groupConstructor === "shared-multi" || groupConstructor === "single-multi"; + + const addGroupValid = + needsNetworks && needsOperators + ? Boolean(groupNetworksCount && groupOperatorsCount) + : needsNetworks + ? Boolean(groupNetworksCount) + : needsOperators + ? Boolean(groupOperatorsCount) + : true; + + const swapScope = useMemo((): { label: string; items: Array } => { + if (zoom.kind === "all") return { label: "Groups", items: model.groups }; + const group = model.groups.find((g) => g.id === zoom.groupId); + if (!group) return { label: "Groups", items: [] as GroupSlot[] }; + if (zoom.kind === "group") return { label: "Networks", items: group.networks }; + const network = group.networks.find((n) => n.id === zoom.networkId); + if (!network) return { label: "Networks", items: [] as NetworkSlot[] }; + return { label: "Operators", items: network.operators }; + }, [model.groups, zoom]); + + const swapCandidates = useMemo(() => { + const items = swapScope.items; + if (items.length < 2) return []; + const out: Array<{ + id: string; + label: string; + leftId: string; + rightId: string; + leftIndex: bigint | null; + rightIndex: bigint | null; + }> = []; + for (let i = 0; i < items.length - 1; i += 1) { + const left = items[i]; + const right = items[i + 1]; + if (!left || !right) continue; + const leftIndex = left.index ?? null; + const rightIndex = right.index ?? null; + const leftDisplay = slotIdToIndex.get(left.id); + const rightDisplay = slotIdToIndex.get(right.id); + const leftLabel = leftDisplay ? getChildIndex(leftDisplay).toString() : `${i + 1}`; + const rightLabel = rightDisplay ? getChildIndex(rightDisplay).toString() : `${i + 2}`; + out.push({ + id: `${left.id}:${right.id}`, + label: `${swapScope.label.slice(0, -1)} ${leftLabel} <-> ${swapScope.label.slice(0, -1)} ${rightLabel}`, + leftId: left.id, + rightId: right.id, + leftIndex, + rightIndex, + }); + } + return out; + }, [slotIdToIndex, swapScope.items, swapScope.label]); + + useEffect(() => { + if (swapCandidates.length === 0) { + setSwapCandidateId(""); + return; + } + if (!swapCandidates.find((candidate) => candidate.id === swapCandidateId)) { + setSwapCandidateId(swapCandidates[0]!.id); + } + }, [swapCandidates, swapCandidateId]); + + return ( +
+ {toastMessage ? ( +
+
+ {toastMessage} +
+
+ ) : null} +
+
+
UniversalDelegator Configurator
+
+
+
+
+ + {walletStatusLabel} +
+ {walletConnected ? ( +
+ + {shortAccountAddress} + + {chainLabel} +
+ ) : null} +
+ {authenticated ? ( + + ) : ( + + )} +
+
+ +
+
+
+
+
+
+
Multicall
+
{encodedCalls.length} call(s) queued
+
+ Strategy: {selectedCandidateLabel} + {selectedCandidateLabel !== primaryCandidateLabel ? " (fallback)" : null} +
+
+
+ {isValidatingMulticall ? ( +
+ Validating multicall against on-chain state… +
+ ) : null} + +
+
+ + {multicallWarning ? ( +
+ {multicallWarning} +
+ ) : null} + + {(isPending || isConfirming || isConfirmed || error) && ( +
+ {txHash ?
{txHash}
: null} +
+ {error ? ( +
{error.message}
+ ) : isConfirmed ? ( +
Confirmed
+ ) : isConfirming ? ( +
Waiting for confirmation…
+ ) : isPending ? ( +
Waiting for wallet approval…
+ ) : null} +
+
+ )} + +
Ops
+
+ {selectedOps.length === 0 ? ( +
No operations yet.
+ ) : ( +
    + {selectedOps.map((op, i) => ( +
  1. + {formatOp(op)} +
  2. + ))} +
+ )} +
+ +
+ + {multicallError ?
{multicallError}
: null} +
+
+
+ +
+
+
+
+
Delegator Address
+ setDelegatorAddress(e.target.value)} + /> + {isReconstructing ? ( +
+ + Loading on-chain slots… +
+ ) : null} + {reconstructError ?
{reconstructError}
: null} +
+
+ +
+
+
+
Add Group
+
+ + + {needsNetworks ? ( + + ) : null} + + {needsOperators ? ( + + ) : null} +
+ +
+
+ +
+
+
Swap Slots
+
Scope: {swapScope.label}
+ {swapCandidates.length === 0 ? ( +
No neighbor slots to swap.
+ ) : ( + + )} + +
+
+
+ +
+
+ {zoomCrumbs.length > 0 ? ( +
+ Viewing + {zoomCrumbs.map((crumb, idx) => { + const isCurrent = + (crumb.kind === "groups" && zoom.kind === "all") || + (crumb.kind === "group" && zoom.kind === "group") || + (crumb.kind === "network" && zoom.kind === "network"); + const label = isCurrent ? ( + {crumb.label} + ) : ( + + ); + return ( + + {idx > 0 ? / : null} + {label} + + ); + })} + {zoom.kind === "all" ? / : null} +
+ ) : null} +
+
+ + +
+
+ +
+
+ Allocated: {canReadBalances ? (rootBalance?.toString() ?? (balancesLoading ? "loading…" : "—")) : "—"} +
+
+ +
+
+ {visibleGroups.map((group, groupPos) => { + const draft = group.state.draft; + const groupIndex = slotIdToIndex.get(group.id); + const sizeValid = parseUint(draft.size) !== null; + const widthSizeValue = groupSizeValues[groupPos] ?? 0n; + const groupGrow = flexGrowFromSize(widthSizeValue, groupTotalSize); + const fillSizeValue = effectiveSize(group.state); + const allocatedRaw = + groupIndex !== undefined ? (allocationsByIndex.get(groupIndex.toString()) ?? 0n) : 0n; + const pendingRaw = + groupIndex !== undefined ? (pendingByIndex.get(groupIndex.toString()) ?? 0n) : 0n; + const pendingValue = pendingRaw > allocatedRaw ? allocatedRaw : pendingRaw; + const allocatedValue = saturatingSub(allocatedRaw, pendingValue); + const allocatedPct = + fillSizeValue > 0n ? Math.min(100, Number((allocatedValue * 10000n) / fillSizeValue) / 100) : 0; + const pendingPctRaw = + fillSizeValue > 0n ? Number((pendingValue * 10000n) / fillSizeValue) / 100 : 0; + const pendingPct = Math.max(0, Math.min(100 - allocatedPct, pendingPctRaw)); + const isGroupFocused = zoom.kind !== "all" && zoom.groupId === group.id; + const isGroupHovered = hoveredGroupId === group.id; + const handleGroupClick = (event: MouseEvent) => { + if (isInteractiveTarget(event.target)) return; + setZoom((prev) => + prev.kind === "group" && prev.groupId === group.id + ? { kind: "all" } + : { kind: "group", groupId: group.id }, + ); + }; + const handleGroupHover = (event: MouseEvent) => { + const target = event.target as HTMLElement | null; + const isOverNetwork = Boolean(target && target.closest("[data-network-card]")); + if (isOverNetwork) { + setHoveredGroupId((prev) => (prev === group.id ? null : prev)); + return; + } + setHoveredGroupId((prev) => (prev === group.id ? prev : group.id)); + }; + const handleGroupLeave = () => { + setHoveredGroupId((prev) => (prev === group.id ? null : prev)); + }; + + return ( +
+
+ {pendingPct > 0 ? ( +
+ ) : null} +
+
+
+
+ {groupIndex !== undefined ? ( + + ) : null} +
Group
+
+
+
+ Allocated:{" "} + {!canReadBalances || !hasRootBalance || groupIndex === undefined + ? "—" + : allocationsLoading || pendingLoading + ? "loading…" + : allocatedValue.toString()} +
+
+ Pending:{" "} + {!canReadBalances || !hasRootBalance || groupIndex === undefined + ? "—" + : pendingLoading + ? "loading…" + : pendingValue.toString()} +
+
+
+ +
+ + + +
+
+ + addDraftNetwork(group.id)} + showAddNetwork={zoom.kind !== "network"} + focusedNetworkId={zoom.kind === "network" ? zoom.networkId : null} + onZoomNetwork={(networkId) => + setZoom((prev) => + prev.kind === "network" && prev.networkId === networkId + ? { kind: "group", groupId: group.id } + : { kind: "network", groupId: group.id, networkId }, + ) + } + onUpdateNetworkDraft={(networkId, patch) => updateNetworkDraft(group.id, networkId, patch)} + onAddOperator={(networkId) => addDraftOperator(group.id, networkId)} + onUpdateOperatorDraft={(networkId, operatorId, patch) => + updateOperatorDraft(group.id, networkId, operatorId, patch) + } + /> +
+
+ ); + })} + + {zoom.kind === "all" ? ( + + ) : null} +
+
+
+
+
+
+
+ ); +} + +function formatOp(op: UdOperation): string { + if (op.kind === "createSlot") { + return `createSlot(${formatIndex(op.parentIndex)}, ${op.isShared}, ${op.size})`; + } + if (op.kind === "setIsShared") { + return `setIsShared(${formatIndex(op.index)}, ${op.isShared})`; + } + if (op.kind === "setSize") { + return `setSize(${formatIndex(op.index)}, ${op.size})`; + } + if (op.kind === "swapSlots") { + return `swapSlots(${formatIndex(op.index1)}, ${formatIndex(op.index2)})`; + } + if (op.kind === "assignNetwork") { + return `assignNetwork(${formatIndex(op.index)}, ${op.subnetwork})`; + } + if (op.kind === "unassignNetwork") { + return `unassignNetwork(${op.subnetwork})`; + } + if (op.kind === "assignOperator") { + return `assignOperator(${formatIndex(op.index)}, ${op.operator})`; + } + return `unassignOperator(${formatIndex(op.parentIndex)}, ${op.operator})`; +} + +function opToJson(op: UdOperation): Record { + if (op.kind === "createSlot") { + return { + kind: op.kind, + parentIndex: formatIndex(op.parentIndex), + isShared: op.isShared, + size: op.size.toString(), + }; + } + if (op.kind === "setIsShared") { + return { kind: op.kind, index: formatIndex(op.index), isShared: op.isShared }; + } + if (op.kind === "setSize") { + return { kind: op.kind, index: formatIndex(op.index), size: op.size.toString() }; + } + if (op.kind === "swapSlots") { + return { + kind: op.kind, + index1: formatIndex(op.index1), + index2: formatIndex(op.index2), + }; + } + if (op.kind === "assignNetwork") { + return { kind: op.kind, index: formatIndex(op.index), subnetwork: op.subnetwork }; + } + if (op.kind === "unassignNetwork") { + return { kind: op.kind, subnetwork: op.subnetwork }; + } + if (op.kind === "assignOperator") { + return { kind: op.kind, index: formatIndex(op.index), operator: op.operator }; + } + return { + kind: op.kind, + parentIndex: formatIndex(op.parentIndex), + operator: op.operator, + }; +} + +function NetworksRow(props: { + group: GroupSlot; + slotIdToIndex: Map; + allocatedByIndex: Map; + pendingByIndex: Map; + allocationsLoading: boolean; + pendingLoading: boolean; + canReadBalances: boolean; + hasRootBalance: boolean; + onCopyIndex: (index: bigint) => void; + onAddNetwork: () => void; + showAddNetwork?: boolean; + focusedNetworkId?: string | null; + onZoomNetwork?: (networkId: string) => void; + onUpdateNetworkDraft: (networkId: string, patch: Partial) => void; + onAddOperator: (networkId: string) => void; + onUpdateOperatorDraft: (networkId: string, operatorId: string, patch: Partial) => void; +}) { + const isShared = props.group.state.draft.isShared; + const hasNetworks = props.group.networks.length > 0; + const showAddNetwork = props.showAddNetwork ?? true; + const focusedNetworkId = props.focusedNetworkId ?? null; + const [hoveredNetworkId, setHoveredNetworkId] = useState(null); + const networksLayoutClass = isShared + ? "flex flex-col items-start gap-3" + : "flex flex-row flex-nowrap gap-3 overflow-x-auto pb-2"; + + const networkSizeValues = props.group.networks.map((network) => effectiveSize(network.state)); + const networksTotalSize = sumBigints(networkSizeValues); + const networksMaxSize = maxBigint(networkSizeValues); + + const addButtonRef = useRef(null); + const prevNetworksCount = useRef(props.group.networks.length); + useEffect(() => { + const current = props.group.networks.length; + if (current > prevNetworksCount.current && addButtonRef.current) { + addButtonRef.current.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "end" }); + } + prevNetworksCount.current = current; + }, [props.group.networks.length]); + + return ( +
+
+ {props.group.networks.map((network, networkPos) => { + const draft = network.state.draft; + const networkIndex = props.slotIdToIndex.get(network.id); + const sizeValid = parseUint(draft.size) !== null; + const widthSizeValue = networkSizeValues[networkPos] ?? 0n; + const networkGrow = flexGrowFromSize(widthSizeValue, networksTotalSize); + const networkWidthPct = percentWidthFromSize(widthSizeValue, networksMaxSize, 60, 100); + const fillSizeValue = effectiveSize(network.state); + const allocatedRaw = + networkIndex !== undefined ? (props.allocatedByIndex.get(networkIndex.toString()) ?? 0n) : 0n; + const pendingRaw = + networkIndex !== undefined ? (props.pendingByIndex.get(networkIndex.toString()) ?? 0n) : 0n; + const pendingValue = pendingRaw > allocatedRaw ? allocatedRaw : pendingRaw; + const allocatedValue = saturatingSub(allocatedRaw, pendingValue); + const allocatedPct = + fillSizeValue > 0n ? Math.min(100, Number((allocatedValue * 10000n) / fillSizeValue) / 100) : 0; + const pendingPctRaw = fillSizeValue > 0n ? Number((pendingValue * 10000n) / fillSizeValue) / 100 : 0; + const pendingPct = Math.max(0, Math.min(100 - allocatedPct, pendingPctRaw)); + const subnetworkTrimmed = draft.subnetwork.trim(); + const subnetworkValid = subnetworkTrimmed === "" || parseBytes32(subnetworkTrimmed) !== null; + const isFocused = focusedNetworkId === network.id; + const isNetworkHovered = hoveredNetworkId === network.id; + const handleNetworkClick = (event: MouseEvent) => { + event.stopPropagation(); + if (isInteractiveTarget(event.target)) return; + if (!props.onZoomNetwork) return; + props.onZoomNetwork(network.id); + }; + const handleNetworkHover = (event: MouseEvent) => { + const target = event.target as HTMLElement | null; + const isOverNoZoom = Boolean(target && target.closest("[data-no-zoom]")); + if (isOverNoZoom) { + setHoveredNetworkId((prev) => (prev === network.id ? null : prev)); + return; + } + setHoveredNetworkId((prev) => (prev === network.id ? prev : network.id)); + }; + const handleNetworkLeave = () => { + setHoveredNetworkId((prev) => (prev === network.id ? null : prev)); + }; + return ( +
+
+ {pendingPct > 0 ? ( +
+ ) : null} +
+
+
+
+ {networkIndex !== undefined ? ( + + ) : null} +
Network
+
+
+
+ Allocated:{" "} + {!props.canReadBalances || !props.hasRootBalance || networkIndex === undefined + ? "—" + : props.allocationsLoading || props.pendingLoading + ? "loading…" + : allocatedValue.toString()} +
+
+ Pending:{" "} + {!props.canReadBalances || !props.hasRootBalance || networkIndex === undefined + ? "—" + : props.pendingLoading + ? "loading…" + : pendingValue.toString()} +
+
+ props.onUpdateNetworkDraft(network.id, { subnetwork: e.target.value })} + /> +
+ + +
+ + props.onAddOperator(network.id)} + onUpdateOperatorDraft={(operatorId, patch) => + props.onUpdateOperatorDraft(network.id, operatorId, patch) + } + /> +
+
+ ); + })} + + {showAddNetwork ? ( + + ) : null} +
+
+ ); +} + +function OperatorsRow(props: { + network: NetworkSlot; + slotIdToIndex: Map; + allocatedByIndex: Map; + allocationsLoading: boolean; + pendingByIndex: Map; + pendingLoading: boolean; + canReadBalances: boolean; + hasRootBalance: boolean; + onCopyIndex: (index: bigint) => void; + onAddOperator: () => void; + onUpdateOperatorDraft: (operatorId: string, patch: Partial) => void; +}) { + const hasOperators = props.network.operators.length > 0; + const addButtonRef = useRef(null); + const prevOperatorsCount = useRef(props.network.operators.length); + useEffect(() => { + const current = props.network.operators.length; + if (current > prevOperatorsCount.current && addButtonRef.current) { + addButtonRef.current.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "end" }); + } + prevOperatorsCount.current = current; + }, [props.network.operators.length]); + + const operatorSizeValues = props.network.operators.map((operator) => effectiveSize(operator.state)); + const operatorsTotalSize = sumBigints(operatorSizeValues); + + return ( +
+
+ {props.network.operators.map((operator, operatorPos) => { + const draft = operator.state.draft; + const operatorIndex = props.slotIdToIndex.get(operator.id); + const sizeValid = parseUint(draft.size) !== null; + const widthSizeValue = operatorSizeValues[operatorPos] ?? 0n; + const operatorGrow = flexGrowFromSize(widthSizeValue, operatorsTotalSize); + const fillSizeValue = effectiveSize(operator.state); + const allocatedRaw = + operatorIndex !== undefined ? (props.allocatedByIndex.get(operatorIndex.toString()) ?? 0n) : 0n; + const pendingRaw = + operatorIndex !== undefined ? (props.pendingByIndex.get(operatorIndex.toString()) ?? 0n) : 0n; + const pendingValue = pendingRaw > allocatedRaw ? allocatedRaw : pendingRaw; + const allocatedValue = saturatingSub(allocatedRaw, pendingValue); + const allocatedPct = + fillSizeValue > 0n ? Math.min(100, Number((allocatedValue * 10000n) / fillSizeValue) / 100) : 0; + const pendingPctRaw = fillSizeValue > 0n ? Number((pendingValue * 10000n) / fillSizeValue) / 100 : 0; + const pendingPct = Math.max(0, Math.min(100 - allocatedPct, pendingPctRaw)); + const operatorTrimmed = draft.operator.trim(); + const operatorValid = operatorTrimmed === "" || isAddress(operatorTrimmed); + return ( +
+
+ {pendingPct > 0 ? ( +
+ ) : null} +
+
+
+
+ {operatorIndex !== undefined ? ( + + ) : null} +
Operator
+
+
+
+ Allocated:{" "} + {!props.canReadBalances || !props.hasRootBalance || operatorIndex === undefined + ? "—" + : props.allocationsLoading || props.pendingLoading + ? "loading…" + : allocatedValue.toString()} +
+
+ Pending:{" "} + {!props.canReadBalances || !props.hasRootBalance || operatorIndex === undefined + ? "—" + : props.pendingLoading + ? "loading…" + : pendingValue.toString()} +
+
+ props.onUpdateOperatorDraft(operator.id, { operator: e.target.value })} + /> +
+ + +
+
+
+ ); + })} + + +
+
+ ); +} diff --git a/ui/src/utils/universalDelegatorIndex.ts b/ui/src/utils/universalDelegatorIndex.ts new file mode 100644 index 00000000..bd38f92b --- /dev/null +++ b/ui/src/utils/universalDelegatorIndex.ts @@ -0,0 +1,51 @@ +const MASK_32 = (1n << 32n) - 1n +const MASK_64 = (1n << 64n) - 1n +const MASK_96 = (1n << 96n) - 1n + +export type UniversalDelegatorDepth = 0 | 1 | 2 | 3 + +export function getDepth(index: bigint): UniversalDelegatorDepth { + if (index === 0n) return 0 + if ((index & MASK_64) === 0n) return 1 + if ((index & MASK_32) === 0n) return 2 + return 3 +} + +export function createIndex(parentIndex: bigint, localIndex: bigint): bigint { + if (localIndex === 0n) { + throw new Error('ZeroIndex') + } + + const depth = getDepth(parentIndex) + if (depth === 0) return localIndex << 64n + if (depth === 1) return parentIndex | (localIndex << 32n) + if (depth === 2) return parentIndex | localIndex + throw new Error('NotParentIndex') +} + +export function getParentIndex(index: bigint): bigint { + if (index === 0n) { + throw new Error('ZeroIndex') + } + + const depth = getDepth(index) + if (depth === 1) return 0n + if (depth === 2) return index & (MASK_96 ^ MASK_64) + return index & (MASK_96 ^ MASK_32) +} + +export function getChildIndex(index: bigint): bigint { + if (index === 0n) { + throw new Error('ZeroIndex') + } + + const depth = getDepth(index) + if (depth === 1) return (index >> 64n) & MASK_32 + if (depth === 2) return (index >> 32n) & MASK_32 + return index & MASK_32 +} + +export function formatIndex(index: bigint): string { + return `0x${index.toString(16).padStart(24, '0')}` +} + diff --git a/ui/src/web3/config.ts b/ui/src/web3/config.ts new file mode 100644 index 00000000..04c1e398 --- /dev/null +++ b/ui/src/web3/config.ts @@ -0,0 +1,28 @@ +import { createConfig } from "@privy-io/wagmi"; +import { http } from "wagmi"; +import { anvil, mainnet, sepolia } from "wagmi/chains"; + +const httpTransport = (url?: string) => (url ? http(url) : http()); + +export const wagmiConfig = createConfig({ + chains: [anvil, sepolia, mainnet], + batch: { + multicall: { + batchSize: 16_384, + deployless: true, + }, + }, + transports: { + [anvil.id]: httpTransport( + import.meta.env.VITE_ANVIL_RPC_URL ?? import.meta.env.VITE_RPC_URL ?? "http://127.0.0.1:8545", + ), + [sepolia.id]: httpTransport(import.meta.env.VITE_SEPOLIA_RPC_URL ?? import.meta.env.VITE_RPC_URL), + [mainnet.id]: httpTransport(import.meta.env.VITE_MAINNET_RPC_URL ?? import.meta.env.VITE_RPC_URL), + }, +}); + +declare module "wagmi" { + interface Register { + config: typeof wagmiConfig; + } +} diff --git a/ui/tailwind.config.ts b/ui/tailwind.config.ts new file mode 100644 index 00000000..a4eed2fe --- /dev/null +++ b/ui/tailwind.config.ts @@ -0,0 +1,14 @@ +import type { Config } from 'tailwindcss' +import daisyui from 'daisyui' + +export default { + content: ['./index.html', './src/**/*.{ts,tsx,js,jsx}'], + theme: { + extend: {}, + }, + plugins: [daisyui], + daisyui: { + themes: ['light', 'dark'], + }, +} satisfies Config + diff --git a/ui/tsconfig.app.json b/ui/tsconfig.app.json new file mode 100644 index 00000000..a9b5a59c --- /dev/null +++ b/ui/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/ui/tsconfig.json b/ui/tsconfig.json new file mode 100644 index 00000000..1ffef600 --- /dev/null +++ b/ui/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/ui/tsconfig.node.json b/ui/tsconfig.node.json new file mode 100644 index 00000000..8a67f62f --- /dev/null +++ b/ui/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/ui/vite.config.ts b/ui/vite.config.ts new file mode 100644 index 00000000..dd54e7f6 --- /dev/null +++ b/ui/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [tailwindcss(), react()], +}) From ef585a4c0241d41364c85f4700e09dce9337fbc3 Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 23 Dec 2025 22:22:33 +0400 Subject: [PATCH 03/10] refactor: separate logic and frontend --- ui/package.json | 36 +- ui/pnpm-lock.yaml | 10160 ++++++++++++++++ .../pages/UniversalDelegatorConfigurator.tsx | 2019 +-- ui/src/pages/universalDelegator/logic.ts | 1682 +++ 4 files changed, 12059 insertions(+), 1838 deletions(-) create mode 100644 ui/pnpm-lock.yaml create mode 100644 ui/src/pages/universalDelegator/logic.ts diff --git a/ui/package.json b/ui/package.json index cbf0bcba..96b2ba72 100644 --- a/ui/package.json +++ b/ui/package.json @@ -10,34 +10,40 @@ "preview": "vite preview" }, "dependencies": { - "@privy-io/react-auth": "^3.9.0", - "@privy-io/wagmi": "^2.1.1", + "@privy-io/react-auth": "^3.9.1", + "@privy-io/wagmi": "^2.1.2", "@tailwindcss/vite": "^4.1.18", "@tanstack/react-query": "^5.90.12", - "react": "^19.2.0", - "react-dom": "^19.2.0", + "react": "^19.2.3", + "react-dom": "^19.2.3", "tailwindcss": "^4.1.18", - "viem": "~2.41.2", + "viem": "~2.43.3", "wagmi": "^3.1.0" }, "devDependencies": { - "@eslint/js": "^9.39.1", - "@types/node": "^24.10.1", - "@types/react": "^19.2.5", + "@eslint/js": "^9.39.2", + "@types/node": "^25.0.3", + "@types/react": "^19.2.7", "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^5.1.1", + "@vitejs/plugin-react": "^5.1.2", "daisyui": "^5.5.14", - "eslint": "^9.39.1", + "eslint": "^9.39.2", "eslint-plugin-react-hooks": "^7.0.1", - "eslint-plugin-react-refresh": "^0.4.24", + "eslint-plugin-react-refresh": "^0.4.26", "globals": "^16.5.0", "typescript": "~5.9.3", - "typescript-eslint": "^8.46.4", - "vite": "npm:rolldown-vite@7.2.5" + "typescript-eslint": "^8.50.1", + "vite": "npm:rolldown-vite@7.3.0" }, "pnpm": { "overrides": { - "vite": "npm:rolldown-vite@7.2.5" - } + "vite": "npm:rolldown-vite@7.3.0" + }, + "onlyBuiltDependencies": [ + "@reown/appkit", + "bufferutil", + "keccak", + "utf-8-validate" + ] } } diff --git a/ui/pnpm-lock.yaml b/ui/pnpm-lock.yaml new file mode 100644 index 00000000..8c5e408e --- /dev/null +++ b/ui/pnpm-lock.yaml @@ -0,0 +1,10160 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +overrides: + vite: npm:rolldown-vite@7.3.0 + +importers: + + .: + dependencies: + '@privy-io/react-auth': + specifier: ^3.9.1 + version: 3.9.1(@solana-program/system@0.8.1(@solana/kit@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10))))(@solana-program/token@0.9.0(@solana/kit@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10))))(@solana/kit@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10)))(@solana/sysvars@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(@tanstack/query-core@5.90.12)(@tanstack/react-query@5.90.12(react@19.2.3))(@types/react@19.2.7)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@4.2.1) + '@privy-io/wagmi': + specifier: ^2.1.2 + version: 2.1.2(f07444eeb19ffb65b1c978d9b01a05d8) + '@tailwindcss/vite': + specifier: ^4.1.18 + version: 4.1.18(rolldown-vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)) + '@tanstack/react-query': + specifier: ^5.90.12 + version: 5.90.12(react@19.2.3) + react: + specifier: ^19.2.3 + version: 19.2.3 + react-dom: + specifier: ^19.2.3 + version: 19.2.3(react@19.2.3) + tailwindcss: + specifier: ^4.1.18 + version: 4.1.18 + viem: + specifier: ~2.43.3 + version: 2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + wagmi: + specifier: ^3.1.0 + version: 3.1.1(e5a60a8fcb871a16ac1f86312b108fb9) + devDependencies: + '@eslint/js': + specifier: ^9.39.2 + version: 9.39.2 + '@types/node': + specifier: ^25.0.3 + version: 25.0.3 + '@types/react': + specifier: ^19.2.7 + version: 19.2.7 + '@types/react-dom': + specifier: ^19.2.3 + version: 19.2.3(@types/react@19.2.7) + '@vitejs/plugin-react': + specifier: ^5.1.2 + version: 5.1.2(rolldown-vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)) + daisyui: + specifier: ^5.5.14 + version: 5.5.14 + eslint: + specifier: ^9.39.2 + version: 9.39.2(jiti@2.6.1) + eslint-plugin-react-hooks: + specifier: ^7.0.1 + version: 7.0.1(eslint@9.39.2(jiti@2.6.1)) + eslint-plugin-react-refresh: + specifier: ^0.4.26 + version: 0.4.26(eslint@9.39.2(jiti@2.6.1)) + globals: + specifier: ^16.5.0 + version: 16.5.0 + typescript: + specifier: ~5.9.3 + version: 5.9.3 + typescript-eslint: + specifier: ^8.50.1 + version: 8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + vite: + specifier: npm:rolldown-vite@7.3.0 + version: rolldown-vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1) + +packages: + + '@adraffy/ens-normalize@1.11.1': + resolution: {integrity: sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ==} + + '@babel/code-frame@7.27.1': + resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.28.5': + resolution: {integrity: sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.28.5': + resolution: {integrity: sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.28.5': + resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.27.2': + resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.27.1': + resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.28.3': + resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-plugin-utils@7.27.1': + resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.27.1': + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.28.4': + resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.28.5': + resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-transform-react-jsx-self@7.27.1': + resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-source@7.27.1': + resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/runtime@7.28.4': + resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} + engines: {node: '>=6.9.0'} + + '@babel/template@7.27.2': + resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.28.5': + resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.28.5': + resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} + engines: {node: '>=6.9.0'} + + '@base-org/account@1.1.1': + resolution: {integrity: sha512-IfVJPrDPhHfqXRDb89472hXkpvJuQQR7FDI9isLPHEqSYt/45whIoBxSPgZ0ssTt379VhQo4+87PWI1DoLSfAQ==} + + '@base-org/account@2.4.0': + resolution: {integrity: sha512-A4Umpi8B9/pqR78D1Yoze4xHyQaujioVRqqO3d6xuDFw9VRtjg6tK3bPlwE0aW+nVH/ntllCpPa2PbI8Rnjcug==} + + '@coinbase/cdp-sdk@1.40.1': + resolution: {integrity: sha512-VZxAUYvWbqM4gw/ZHyr9fKBlCAKdMbBQzJxpV9rMUNkdulHIrj0cko2Mw3dyVyw+gdT62jAVxzVkPuQTRnECLw==} + + '@coinbase/wallet-sdk@3.9.3': + resolution: {integrity: sha512-N/A2DRIf0Y3PHc1XAMvbBUu4zisna6qAdqABMZwBMNEfWrXpAwx16pZGkYCLGE+Rvv1edbcB2LYDRnACNcmCiw==} + + '@coinbase/wallet-sdk@4.3.2': + resolution: {integrity: sha512-hOLA2YONq8Z9n8f6oVP6N//FEEHOen7nq+adG/cReol6juFTHUelVN5GnA5zTIxiLFMDcrhDwwgCA6Tdb5jubw==} + + '@coinbase/wallet-sdk@4.3.6': + resolution: {integrity: sha512-4q8BNG1ViL4mSAAvPAtpwlOs1gpC+67eQtgIwNvT3xyeyFFd+guwkc8bcX5rTmQhXpqnhzC4f0obACbP9CqMSA==} + + '@ecies/ciphers@0.2.5': + resolution: {integrity: sha512-GalEZH4JgOMHYYcYmVqnFirFsjZHeoGMDt9IxEnM9F7GRUUyUksJ7Ou53L83WHJq3RWKD3AcBpo0iQh0oMpf8A==} + engines: {bun: '>=1', deno: '>=2', node: '>=16'} + peerDependencies: + '@noble/ciphers': ^1.0.0 + + '@emnapi/core@1.7.1': + resolution: {integrity: sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==} + + '@emnapi/runtime@1.7.1': + resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} + + '@emnapi/wasi-threads@1.1.0': + resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} + + '@emotion/is-prop-valid@1.2.2': + resolution: {integrity: sha512-uNsoYd37AFmaCdXlg6EYD1KaPOaRWRByMCYzbKUX4+hhMfrxdVSelShywL4JVaAeM/eHUOSprYBQls+/neX3pw==} + + '@emotion/memoize@0.8.1': + resolution: {integrity: sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==} + + '@emotion/unitless@0.8.1': + resolution: {integrity: sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==} + + '@eslint-community/eslint-utils@4.9.0': + resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} + 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.12.2': + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/config-array@0.21.1': + resolution: {integrity: sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/config-helpers@0.4.2': + resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.17.0': + resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/eslintrc@3.3.3': + resolution: {integrity: sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.39.2': + resolution: {integrity: sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.7': + resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.4.1': + resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@ethereumjs/common@3.2.0': + resolution: {integrity: sha512-pksvzI0VyLgmuEF2FA/JR/4/y6hcPq8OUail3/AvycBaW1d5VSauOZzqGvJ3RTmR4MU35lWE8KseKOsEhrFRBA==} + + '@ethereumjs/rlp@4.0.1': + resolution: {integrity: sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw==} + engines: {node: '>=14'} + hasBin: true + + '@ethereumjs/tx@4.2.0': + resolution: {integrity: sha512-1nc6VO4jtFd172BbSnTnDQVr9IYBFl1y4xPzZdtkrkKIncBCkdbgfdRV+MiTkJYAtTxvV12GRZLqBFT1PNK6Yw==} + engines: {node: '>=14'} + + '@ethereumjs/util@8.1.0': + resolution: {integrity: sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA==} + engines: {node: '>=14'} + + '@floating-ui/core@1.7.3': + resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==} + + '@floating-ui/dom@1.7.4': + resolution: {integrity: sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==} + + '@floating-ui/react-dom@2.1.6': + resolution: {integrity: sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@floating-ui/react@0.26.28': + resolution: {integrity: sha512-yORQuuAtVpiRjpMhdc0wJj06b9JFjrYF4qp96j++v2NBpbi6SEGF7donUJ3TMieerQ6qVkAv1tgr7L4r5roTqw==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@floating-ui/utils@0.2.10': + resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} + + '@gemini-wallet/core@0.3.2': + resolution: {integrity: sha512-Z4aHi3ECFf5oWYWM3F1rW83GJfB9OvhBYPTmb5q+VyK3uvzvS48lwo+jwh2eOoCRWEuT/crpb9Vwp2QaS5JqgQ==} + peerDependencies: + viem: '>=2.0.0' + + '@hcaptcha/loader@2.3.0': + resolution: {integrity: sha512-i4lnNxKBe+COf3R1nFZEWaZoHIoJjvDgWqvcNrdZq8ehoSNMN6KVZ56dcQ02qKie2h3+BkbkwlJA9DOIuLlK/g==} + + '@hcaptcha/react-hcaptcha@1.17.1': + resolution: {integrity: sha512-qMp6XrFLy7eXdIQkwLOnEVDm7qnXrB7EgtdqVJ1rfxTGkxtSDipBgP+WdOIeZvVUsniLFmx+Almjl6bi5+l07A==} + peerDependencies: + react: '>= 16.3.0' + react-dom: '>= 16.3.0' + + '@headlessui/react@2.2.9': + resolution: {integrity: sha512-Mb+Un58gwBn0/yWZfyrCh0TJyurtT+dETj7YHleylHk5od3dv2XqETPGWMyQ5/7sYN7oWdyM1u9MvC0OC8UmzQ==} + engines: {node: '>=10'} + peerDependencies: + react: ^18 || ^19 || ^19.0.0-rc + react-dom: ^18 || ^19 || ^19.0.0-rc + + '@heroicons/react@2.2.0': + resolution: {integrity: sha512-LMcepvRaS9LYHJGsF0zzmgKCUim/X3N/DQKc4jepAXJ7l8QxJ1PmxJzqplF2Z3FE4PqBAIGyJAQ/w4B5dsqbtQ==} + peerDependencies: + react: '>= 16 || ^19.0.0-rc' + + '@humanfs/core@0.19.1': + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.7': + resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@lit-labs/ssr-dom-shim@1.4.0': + resolution: {integrity: sha512-ficsEARKnmmW5njugNYKipTm4SFnbik7CXtoencDZzmzo/dQ+2Q0bgkzJuoJP20Aj0F+izzJjOqsnkd6F/o1bw==} + + '@lit/react@1.0.8': + resolution: {integrity: sha512-p2+YcF+JE67SRX3mMlJ1TKCSTsgyOVdAwd/nxp3NuV1+Cb6MWALbN6nT7Ld4tpmYofcE5kcaSY1YBB9erY+6fw==} + peerDependencies: + '@types/react': 17 || 18 || 19 + + '@lit/reactive-element@2.1.1': + resolution: {integrity: sha512-N+dm5PAYdQ8e6UlywyyrgI2t++wFGXfHx+dSJ1oBrg6FAxUj40jId++EaRm80MKX5JnlH1sBsyZ5h0bcZKemCg==} + + '@marsidev/react-turnstile@1.4.0': + resolution: {integrity: sha512-3aR7mh4lATeayWt6GjWuYyLjM0GL148z7/ZQl0rLKGpDYIrWgoU2PYsdAdA9fzH+JysW3Q2OaPfHvv66cwcAZg==} + peerDependencies: + react: ^17.0.2 || ^18.0.0 || ^19.0 + react-dom: ^17.0.2 || ^18.0.0 || ^19.0 + + '@metamask/eth-json-rpc-provider@1.0.1': + resolution: {integrity: sha512-whiUMPlAOrVGmX8aKYVPvlKyG4CpQXiNNyt74vE1xb5sPvmx5oA7B/kOi/JdBvhGQq97U1/AVdXEdk2zkP8qyA==} + engines: {node: '>=14.0.0'} + + '@metamask/json-rpc-engine@7.3.3': + resolution: {integrity: sha512-dwZPq8wx9yV3IX2caLi9q9xZBw2XeIoYqdyihDDDpuHVCEiqadJLwqM3zy+uwf6F1QYQ65A8aOMQg1Uw7LMLNg==} + engines: {node: '>=16.0.0'} + + '@metamask/json-rpc-engine@8.0.2': + resolution: {integrity: sha512-IoQPmql8q7ABLruW7i4EYVHWUbF74yrp63bRuXV5Zf9BQwcn5H9Ww1eLtROYvI1bUXwOiHZ6qT5CWTrDc/t/AA==} + engines: {node: '>=16.0.0'} + + '@metamask/json-rpc-middleware-stream@7.0.2': + resolution: {integrity: sha512-yUdzsJK04Ev98Ck4D7lmRNQ8FPioXYhEUZOMS01LXW8qTvPGiRVXmVltj2p4wrLkh0vW7u6nv0mNl5xzC5Qmfg==} + engines: {node: '>=16.0.0'} + + '@metamask/object-multiplex@2.1.0': + resolution: {integrity: sha512-4vKIiv0DQxljcXwfpnbsXcfa5glMj5Zg9mqn4xpIWqkv6uJ2ma5/GtUfLFSxhlxnR8asRMv8dDmWya1Tc1sDFA==} + engines: {node: ^16.20 || ^18.16 || >=20} + + '@metamask/onboarding@1.0.1': + resolution: {integrity: sha512-FqHhAsCI+Vacx2qa5mAFcWNSrTcVGMNjzxVgaX8ECSny/BJ9/vgXP9V7WF/8vb9DltPeQkxr+Fnfmm6GHfmdTQ==} + + '@metamask/providers@16.1.0': + resolution: {integrity: sha512-znVCvux30+3SaUwcUGaSf+pUckzT5ukPRpcBmy+muBLC0yaWnBcvDqGfcsw6CBIenUdFrVoAFa8B6jsuCY/a+g==} + engines: {node: ^18.18 || >=20} + + '@metamask/rpc-errors@6.4.0': + resolution: {integrity: sha512-1ugFO1UoirU2esS3juZanS/Fo8C8XYocCuBpfZI5N7ECtoG+zu0wF+uWZASik6CkO6w9n/Iebt4iI4pT0vptpg==} + engines: {node: '>=16.0.0'} + + '@metamask/rpc-errors@7.0.2': + resolution: {integrity: sha512-YYYHsVYd46XwY2QZzpGeU4PSdRhHdxnzkB8piWGvJW2xbikZ3R+epAYEL4q/K8bh9JPTucsUdwRFnACor1aOYw==} + engines: {node: ^18.20 || ^20.17 || >=22} + + '@metamask/safe-event-emitter@2.0.0': + resolution: {integrity: sha512-/kSXhY692qiV1MXu6EeOZvg5nECLclxNXcKCxJ3cXQgYuRymRHpdx/t7JXfsK+JLjwA1e1c1/SBrlQYpusC29Q==} + + '@metamask/safe-event-emitter@3.1.2': + resolution: {integrity: sha512-5yb2gMI1BDm0JybZezeoX/3XhPDOtTbcFvpTXM9kxsoZjPZFh4XciqRbpD6N86HYZqWDhEaKUDuOyR0sQHEjMA==} + engines: {node: '>=12.0.0'} + + '@metamask/sdk-analytics@0.0.5': + resolution: {integrity: sha512-fDah+keS1RjSUlC8GmYXvx6Y26s3Ax1U9hGpWb6GSY5SAdmTSIqp2CvYy6yW0WgLhnYhW+6xERuD0eVqV63QIQ==} + + '@metamask/sdk-communication-layer@0.33.1': + resolution: {integrity: sha512-0bI9hkysxcfbZ/lk0T2+aKVo1j0ynQVTuB3sJ5ssPWlz+Z3VwveCkP1O7EVu1tsVVCb0YV5WxK9zmURu2FIiaA==} + peerDependencies: + cross-fetch: ^4.0.0 + eciesjs: '*' + eventemitter2: ^6.4.9 + readable-stream: ^3.6.2 + socket.io-client: ^4.5.1 + + '@metamask/sdk-install-modal-web@0.32.1': + resolution: {integrity: sha512-MGmAo6qSjf1tuYXhCu2EZLftq+DSt5Z7fsIKr2P+lDgdTPWgLfZB1tJKzNcwKKOdf6q9Qmmxn7lJuI/gq5LrKw==} + + '@metamask/sdk@0.33.1': + resolution: {integrity: sha512-1mcOQVGr9rSrVcbKPNVzbZ8eCl1K0FATsYH3WJ/MH4WcZDWGECWrXJPNMZoEAkLxWiMe8jOQBumg2pmcDa9zpQ==} + + '@metamask/superstruct@3.2.1': + resolution: {integrity: sha512-fLgJnDOXFmuVlB38rUN5SmU7hAFQcCjrg3Vrxz67KTY7YHFnSNEKvX4avmEBdOI0yTCxZjwMCFEqsC8k2+Wd3g==} + engines: {node: '>=16.0.0'} + + '@metamask/utils@11.9.0': + resolution: {integrity: sha512-wRnoSDD9jTWOge/+reFviJQANhS+uy8Y+OEwRanp5mQeGTjBFmK1r2cTOnei2UCZRV1crXHzeJVSFEoDDcgRbA==} + engines: {node: ^18.18 || ^20.14 || >=22} + + '@metamask/utils@5.0.2': + resolution: {integrity: sha512-yfmE79bRQtnMzarnKfX7AEJBwFTxvTyw3nBQlu/5rmGXrjAeAMltoGxO62TFurxrQAFMNa/fEjIHNvungZp0+g==} + engines: {node: '>=14.0.0'} + + '@metamask/utils@8.5.0': + resolution: {integrity: sha512-I6bkduevXb72TIM9q2LRO63JSsF9EXduh3sBr9oybNX2hNNpr/j1tEjXrsG0Uabm4MJ1xkGAQEMwifvKZIkyxQ==} + engines: {node: '>=16.0.0'} + + '@metamask/utils@9.3.0': + resolution: {integrity: sha512-w8CVbdkDrVXFJbfBSlDfafDR6BAkpDmv1bC1UJVCoVny5tW2RKAdn9i68Xf7asYT4TnUhl/hN4zfUiKQq9II4g==} + engines: {node: '>=16.0.0'} + + '@msgpack/msgpack@3.1.2': + resolution: {integrity: sha512-JEW4DEtBzfe8HvUYecLU9e6+XJnKDlUAIve8FvPzF3Kzs6Xo/KuZkZJsDH0wJXl/qEZbeeE7edxDNY3kMs39hQ==} + engines: {node: '>= 18'} + + '@napi-rs/wasm-runtime@1.1.0': + resolution: {integrity: sha512-Fq6DJW+Bb5jaWE69/qOE0D1TUN9+6uWhCeZpdnSBk14pjLcCWR7Q8n49PTSPHazM37JqrsdpEthXy2xn6jWWiA==} + + '@noble/ciphers@1.2.1': + resolution: {integrity: sha512-rONPWMC7PeExE077uLE4oqWrZ1IvAfz3oH9LibVAcVCopJiA9R62uavnbEzdkVmJYI6M6Zgkbeb07+tWjlq2XA==} + engines: {node: ^14.21.3 || >=16} + + '@noble/ciphers@1.3.0': + resolution: {integrity: sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==} + engines: {node: ^14.21.3 || >=16} + + '@noble/curves@1.4.2': + resolution: {integrity: sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==} + + '@noble/curves@1.8.0': + resolution: {integrity: sha512-j84kjAbzEnQHaSIhRPUmB3/eVXu2k3dKPl2LOrR8fSOIL+89U+7lV117EWHtq/GHM3ReGHM46iRBdZfpc4HRUQ==} + engines: {node: ^14.21.3 || >=16} + + '@noble/curves@1.8.1': + resolution: {integrity: sha512-warwspo+UYUPep0Q+vtdVB4Ugn8GGQj8iyB3gnRWsztmUHTI3S1nhdiWNsPUGL0vud7JlRRk1XEu7Lq1KGTnMQ==} + engines: {node: ^14.21.3 || >=16} + + '@noble/curves@1.9.1': + resolution: {integrity: sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA==} + engines: {node: ^14.21.3 || >=16} + + '@noble/curves@1.9.6': + resolution: {integrity: sha512-GIKz/j99FRthB8icyJQA51E8Uk5hXmdyThjgQXRKiv9h0zeRlzSCLIzFw6K1LotZ3XuB7yzlf76qk7uBmTdFqA==} + engines: {node: ^14.21.3 || >=16} + + '@noble/curves@1.9.7': + resolution: {integrity: sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==} + engines: {node: ^14.21.3 || >=16} + + '@noble/hashes@1.4.0': + resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} + engines: {node: '>= 16'} + + '@noble/hashes@1.7.0': + resolution: {integrity: sha512-HXydb0DgzTpDPwbVeDGCG1gIu7X6+AuU6Zl6av/E/KG8LMsvPntvq+w17CHRpKBmN6Ybdrt1eP3k4cj8DJa78w==} + engines: {node: ^14.21.3 || >=16} + + '@noble/hashes@1.7.1': + resolution: {integrity: sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==} + engines: {node: ^14.21.3 || >=16} + + '@noble/hashes@1.8.0': + resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} + engines: {node: ^14.21.3 || >=16} + + '@oxc-project/runtime@0.101.0': + resolution: {integrity: sha512-t3qpfVZIqSiLQ5Kqt/MC4Ge/WCOGrrcagAdzTcDaggupjiGxUx4nJF2v6wUCXWSzWHn5Ns7XLv13fCJEwCOERQ==} + engines: {node: ^20.19.0 || >=22.12.0} + + '@oxc-project/types@0.101.0': + resolution: {integrity: sha512-nuFhqlUzJX+gVIPPfuE6xurd4lST3mdcWOhyK/rZO0B9XWMKm79SuszIQEnSMmmDhq1DC8WWVYGVd+6F93o1gQ==} + + '@paulmillr/qr@0.2.1': + resolution: {integrity: sha512-IHnV6A+zxU7XwmKFinmYjUcwlyK9+xkG3/s9KcQhI9BjQKycrJ1JRO+FbNYPwZiPKW3je/DR0k7w8/gLa5eaxQ==} + deprecated: 'The package is now available as "qr": npm install qr' + + '@phosphor-icons/webcomponents@2.1.5': + resolution: {integrity: sha512-JcvQkZxvcX2jK+QCclm8+e8HXqtdFW9xV4/kk2aL9Y3dJA2oQVt+pzbv1orkumz3rfx4K9mn9fDoMr1He1yr7Q==} + + '@privy-io/api-base@1.7.3': + resolution: {integrity: sha512-KAb7P+tfJpUtMYt3R2jrd2cFP4yIby1f/oX1yMU0DhHaKC0xdDPgqoXFkflwiE+5GUARUN1RVP6tUY3AW9RGDA==} + + '@privy-io/api-types@0.3.4': + resolution: {integrity: sha512-OWAMriGX/RygQ74vZZDRFns4wFz5/TxvqXFLtEqQVuwTvXjzo6YkrhKR2qbQADnGkU3SXLHEa3Q7iNfoUKuJ+w==} + + '@privy-io/chains@0.0.5': + resolution: {integrity: sha512-5fOmCOOs7DjGTGnPRv4/2X6/xBKG8fRNrFgNv9ajYdRsKUg86CixszQCYyvZmVxv7XSGrX1oiS1ATAXzfqRmDg==} + + '@privy-io/ethereum@0.0.4': + resolution: {integrity: sha512-OrbMDWBM2CBLt4GRcJ2iDaPMRPdkmOy8jc3mPlr9mZdNxqUFDyfcqifAJ3iR26GfGu+7sU2dU315OfOPz++MSw==} + peerDependencies: + viem: ^2.42.1 + + '@privy-io/js-sdk-core@0.58.4': + resolution: {integrity: sha512-nzRQbPtpzQN1hGmT104/waQUtKF8blkAai45wYUdzc8VP1rFgGQzQNlnHCrHXXnCHJgy+GY2+V7mzrJGUuNQYA==} + peerDependencies: + permissionless: ^0.2.47 + viem: ^2.42.1 + peerDependenciesMeta: + permissionless: + optional: true + viem: + optional: true + + '@privy-io/popup@0.0.1': + resolution: {integrity: sha512-4Z4K5yX9jVzGpx6GgNMlQce35tKfHJwN2A3naTsA82Pff44eVhcQZjaSxj/Y1OKv0hku8WXPwyczhcMfKp1ULg==} + + '@privy-io/react-auth@3.9.1': + resolution: {integrity: sha512-x5RJZBoobv868GdLosp9CFs+8EeAbfLgt1BCSGgmx49jas3gAlZwXdOn7AaIH+WSxqtImFzaOx96chqjbTzSOg==} + peerDependencies: + '@abstract-foundation/agw-client': ^1.0.0 + '@solana-program/memo': '>=0.8.0' + '@solana-program/system': '>=0.8.0' + '@solana-program/token': '>=0.6.0' + '@solana/kit': '>=3.0.3' + permissionless: ^0.2.47 + react: ^18 || ^19 + react-dom: ^18 || ^19 + peerDependenciesMeta: + '@abstract-foundation/agw-client': + optional: true + '@solana-program/memo': + optional: true + '@solana-program/system': + optional: true + '@solana-program/token': + optional: true + '@solana/kit': + optional: true + permissionless: + optional: true + + '@privy-io/routes@0.0.4': + resolution: {integrity: sha512-7rCymSDJBNecJ8Ps8vRcTvPjHu2qAsJzDHndTSyWsFjovtNL2t5AgBUdCffaj2Gn0de0FXNJ23EOJQwzodWOsA==} + + '@privy-io/urls@0.0.2': + resolution: {integrity: sha512-v1LpojKGG9iiFO4HS3kDQ9o2WSf3VGLu9pdAwDuXhnKlHEQ+V2sHtrsA0ZNhC33EhufD7ZOcquAbfG7FxKsQXA==} + + '@privy-io/wagmi@2.1.2': + resolution: {integrity: sha512-KU+rGfquCSo/zviSkz77T3czdanlssqaJX5+xBYqcICdvkP9zbCDvMUt//wM5B0jaQ8NCzUYNWj+j8kcV7MvyA==} + peerDependencies: + '@privy-io/react-auth': ^3.0.0 + react: '>=18' + viem: ^2.42.1 + wagmi: ^2.15.5 + + '@react-aria/focus@3.21.3': + resolution: {integrity: sha512-FsquWvjSCwC2/sBk4b+OqJyONETUIXQ2vM0YdPAuC+QFQh2DT6TIBo6dOZVSezlhudDla69xFBd6JvCFq1AbUw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + + '@react-aria/interactions@3.26.0': + resolution: {integrity: sha512-AAEcHiltjfbmP1i9iaVw34Mb7kbkiHpYdqieWufldh4aplWgsF11YQZOfaCJW4QoR2ML4Zzoa9nfFwLXA52R7Q==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + + '@react-aria/ssr@3.9.10': + resolution: {integrity: sha512-hvTm77Pf+pMBhuBm760Li0BVIO38jv1IBws1xFm1NoL26PU+fe+FMW5+VZWyANR6nYL65joaJKZqOdTQMkO9IQ==} + engines: {node: '>= 12'} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + + '@react-aria/utils@3.32.0': + resolution: {integrity: sha512-/7Rud06+HVBIlTwmwmJa2W8xVtgxgzm0+kLbuFooZRzKDON6hhozS1dOMR/YLMxyJOaYOTpImcP4vRR9gL1hEg==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + + '@react-stately/flags@3.1.2': + resolution: {integrity: sha512-2HjFcZx1MyQXoPqcBGALwWWmgFVUk2TuKVIQxCbRq7fPyWXIl6VHcakCLurdtYC2Iks7zizvz0Idv48MQ38DWg==} + + '@react-stately/utils@3.11.0': + resolution: {integrity: sha512-8LZpYowJ9eZmmYLpudbo/eclIRnbhWIJZ994ncmlKlouNzKohtM8qTC6B1w1pwUbiwGdUoyzLuQbeaIor5Dvcw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + + '@react-types/shared@3.32.1': + resolution: {integrity: sha512-famxyD5emrGGpFuUlgOP6fVW2h/ZaF405G5KDi3zPHzyjAWys/8W6NAVJtNbkCkhedmvL0xOhvt8feGXyXaw5w==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + + '@reown/appkit-common@1.7.8': + resolution: {integrity: sha512-ridIhc/x6JOp7KbDdwGKY4zwf8/iK8EYBl+HtWrruutSLwZyVi5P8WaZa+8iajL6LcDcDF7LoyLwMTym7SRuwQ==} + + '@reown/appkit-common@1.8.9': + resolution: {integrity: sha512-drseYLBDqcQR2WvhfAwrKRiDJdTmsmwZsRBg72sxQDvAwxfKNSmiqsqURq5c/Q9SeeTwclge58Dyq7Ijo6TeeQ==} + + '@reown/appkit-controllers@1.7.8': + resolution: {integrity: sha512-IdXlJlivrlj6m63VsGLsjtPHHsTWvKGVzWIP1fXZHVqmK+rZCBDjCi9j267Rb9/nYRGHWBtlFQhO8dK35WfeDA==} + + '@reown/appkit-controllers@1.8.9': + resolution: {integrity: sha512-/8hgFAgiYCTDG3gSxJr8hXy6GnO28UxN8JOXFUEi5gOODy7d3+3Jwm+7OEghf7hGKrShDedibsXdXKdX1PUT+g==} + + '@reown/appkit-pay@1.7.8': + resolution: {integrity: sha512-OSGQ+QJkXx0FEEjlpQqIhT8zGJKOoHzVnyy/0QFrl3WrQTjCzg0L6+i91Ad5Iy1zb6V5JjqtfIFpRVRWN4M3pw==} + + '@reown/appkit-pay@1.8.9': + resolution: {integrity: sha512-AEmaPqxnzjawSRFenyiTtq0vjKM5IPb2CTD9wa+OMXFpe6FissO+1Eg1H47sfdrycZCvUizSRmQmYqkJaI8BCw==} + + '@reown/appkit-polyfills@1.7.8': + resolution: {integrity: sha512-W/kq786dcHHAuJ3IV2prRLEgD/2iOey4ueMHf1sIFjhhCGMynMkhsOhQMUH0tzodPqUgAC494z4bpIDYjwWXaA==} + + '@reown/appkit-polyfills@1.8.9': + resolution: {integrity: sha512-33YCU8dxe4UkpNf9qCAaHx5crSoEu6tbmZxE/0eEPCYRDRXoiH9VGiN7xwTDOVduacg/U8H6/32ibmYZKnRk5Q==} + + '@reown/appkit-scaffold-ui@1.7.8': + resolution: {integrity: sha512-RCeHhAwOrIgcvHwYlNWMcIDibdI91waaoEYBGw71inE0kDB8uZbE7tE6DAXJmDkvl0qPh+DqlC4QbJLF1FVYdQ==} + + '@reown/appkit-scaffold-ui@1.8.9': + resolution: {integrity: sha512-F7PSM1nxvlvj2eu8iL355GzvCNiL8RKiCqT1zag8aB4QpxjU24l+vAF6debtkg4HY8nJOyDifZ7Z1jkKrHlIDQ==} + + '@reown/appkit-ui@1.7.8': + resolution: {integrity: sha512-1hjCKjf6FLMFzrulhl0Y9Vb9Fu4royE+SXCPSWh4VhZhWqlzUFc7kutnZKx8XZFVQH4pbBvY62SpRC93gqoHow==} + + '@reown/appkit-ui@1.8.9': + resolution: {integrity: sha512-WR17ql77KOMKfyDh7RW4oSfmj+p5gIl0u8Wmopzbx5Hd0HcPVZ5HmTDpwOM9WCSxYcin0fsSAoI+nVdvrhWNtw==} + + '@reown/appkit-utils@1.7.8': + resolution: {integrity: sha512-8X7UvmE8GiaoitCwNoB86pttHgQtzy4ryHZM9kQpvjQ0ULpiER44t1qpVLXNM4X35O0v18W0Dk60DnYRMH2WRw==} + peerDependencies: + valtio: 1.13.2 + + '@reown/appkit-utils@1.8.9': + resolution: {integrity: sha512-U9hx4h7tIE7ha/QWKjZpZc/imaLumdwe0QNdku9epjp/npXVjGuwUrW5mj8yWNSkjtQpY/BEItNdDAUKZ7rrjw==} + peerDependencies: + valtio: 2.1.7 + + '@reown/appkit-wallet@1.7.8': + resolution: {integrity: sha512-kspz32EwHIOT/eg/ZQbFPxgXq0B/olDOj3YMu7gvLEFz4xyOFd/wgzxxAXkp5LbG4Cp++s/elh79rVNmVFdB9A==} + + '@reown/appkit-wallet@1.8.9': + resolution: {integrity: sha512-rcAXvkzOVG4941eZVCGtr2dSJAMOclzZGSe+8hnOUnhK4zxa5svxiP6K9O5SMBp3MrAS3WNsRj5hqx6+JHb7iA==} + + '@reown/appkit@1.7.8': + resolution: {integrity: sha512-51kTleozhA618T1UvMghkhKfaPcc9JlKwLJ5uV+riHyvSoWPKPRIa5A6M1Wano5puNyW0s3fwywhyqTHSilkaA==} + + '@reown/appkit@1.8.9': + resolution: {integrity: sha512-e3N2DAzf3Xv3jnoD8IsUo0/Yfwuhk7npwJBe1+9rDJIRwgPsyYcCLD4gKPDFC5IUIfOLqK7YtGOh9oPEUnIWpw==} + + '@rolldown/binding-android-arm64@1.0.0-beta.53': + resolution: {integrity: sha512-Ok9V8o7o6YfSdTTYA/uHH30r3YtOxLD6G3wih/U9DO0ucBBFq8WPt/DslU53OgfteLRHITZny9N/qCUxMf9kjQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.0.0-beta.53': + resolution: {integrity: sha512-yIsKqMz0CtRnVa6x3Pa+mzTihr4Ty+Z6HfPbZ7RVbk1Uxnco4+CUn7Qbm/5SBol1JD/7nvY8rphAgyAi7Lj6Vg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.0.0-beta.53': + resolution: {integrity: sha512-GTXe+mxsCGUnJOFMhfGWmefP7Q9TpYUseHvhAhr21nCTgdS8jPsvirb0tJwM3lN0/u/cg7bpFNa16fQrjKrCjQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.0.0-beta.53': + resolution: {integrity: sha512-9Tmp7bBvKqyDkMcL4e089pH3RsjD3SUungjmqWtyhNOxoQMh0fSmINTyYV8KXtE+JkxYMPWvnEt+/mfpVCkk8w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.53': + resolution: {integrity: sha512-a1y5fiB0iovuzdbjUxa7+Zcvgv+mTmlGGC4XydVIsyl48eoxgaYkA3l9079hyTyhECsPq+mbr0gVQsFU11OJAQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.53': + resolution: {integrity: sha512-bpIGX+ov9PhJYV+wHNXl9rzq4F0QvILiURn0y0oepbQx+7stmQsKA0DhPGwmhfvF856wq+gbM8L92SAa/CBcLg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@rolldown/binding-linux-arm64-musl@1.0.0-beta.53': + resolution: {integrity: sha512-bGe5EBB8FVjHBR1mOLOPEFg1Lp3//7geqWkU5NIhxe+yH0W8FVrQ6WRYOap4SUTKdklD/dC4qPLREkMMQ855FA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@rolldown/binding-linux-x64-gnu@1.0.0-beta.53': + resolution: {integrity: sha512-qL+63WKVQs1CMvFedlPt0U9PiEKJOAL/bsHMKUDS6Vp2Q+YAv/QLPu8rcvkfIMvQ0FPU2WL0aX4eWwF6e/GAnA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@rolldown/binding-linux-x64-musl@1.0.0-beta.53': + resolution: {integrity: sha512-VGl9JIGjoJh3H8Mb+7xnVqODajBmrdOOb9lxWXdcmxyI+zjB2sux69br0hZJDTyLJfvBoYm439zPACYbCjGRmw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@rolldown/binding-openharmony-arm64@1.0.0-beta.53': + resolution: {integrity: sha512-B4iIserJXuSnNzA5xBLFUIjTfhNy7d9sq4FUMQY3GhQWGVhS2RWWzzDnkSU6MUt7/aHUrep0CdQfXUJI9D3W7A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-wasm32-wasi@1.0.0-beta.53': + resolution: {integrity: sha512-BUjAEgpABEJXilGq/BPh7jeU3WAJ5o15c1ZEgHaDWSz3LB881LQZnbNJHmUiM4d1JQWMYYyR1Y490IBHi2FPJg==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.53': + resolution: {integrity: sha512-s27uU7tpCWSjHBnxyVXHt3rMrQdJq5MHNv3BzsewCIroIw3DJFjMH1dzCPPMUFxnh1r52Nf9IJ/eWp6LDoyGcw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.0.0-beta.53': + resolution: {integrity: sha512-cjWL/USPJ1g0en2htb4ssMjIycc36RvdQAx1WlXnS6DpULswiUTVXPDesTifSKYSyvx24E0YqQkEm0K/M2Z/AA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.0-beta.53': + resolution: {integrity: sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==} + + '@safe-global/safe-apps-provider@0.18.6': + resolution: {integrity: sha512-4LhMmjPWlIO8TTDC2AwLk44XKXaK6hfBTWyljDm0HQ6TWlOEijVWNrt2s3OCVMSxlXAcEzYfqyu1daHZooTC2Q==} + + '@safe-global/safe-apps-sdk@9.1.0': + resolution: {integrity: sha512-N5p/ulfnnA2Pi2M3YeWjULeWbjo7ei22JwU/IXnhoHzKq3pYCN6ynL9mJBOlvDVv892EgLPCWCOwQk/uBT2v0Q==} + + '@safe-global/safe-gateway-typescript-sdk@3.23.1': + resolution: {integrity: sha512-6ORQfwtEJYpalCeVO21L4XXGSdbEMfyp2hEv6cP82afKXSwvse6d3sdelgaPWUxHIsFRkWvHDdzh8IyyKHZKxw==} + engines: {node: '>=16'} + + '@scure/base@1.1.9': + resolution: {integrity: sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==} + + '@scure/base@1.2.6': + resolution: {integrity: sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==} + + '@scure/bip32@1.4.0': + resolution: {integrity: sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==} + + '@scure/bip32@1.6.2': + resolution: {integrity: sha512-t96EPDMbtGgtb7onKKqxRLfE5g05k7uHnHRM2xdE6BP/ZmxaLtPek4J4KfVn/90IQNrU1IOAqMgiDtUdtbe3nw==} + + '@scure/bip32@1.7.0': + resolution: {integrity: sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==} + + '@scure/bip39@1.3.0': + resolution: {integrity: sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==} + + '@scure/bip39@1.5.4': + resolution: {integrity: sha512-TFM4ni0vKvCfBpohoh+/lY05i9gRbSwXWngAsF4CABQxoaOHijxuaZ2R6cStDQ5CHtHO9aGJTr4ksVJASRRyMA==} + + '@scure/bip39@1.6.0': + resolution: {integrity: sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==} + + '@simplewebauthn/browser@13.2.2': + resolution: {integrity: sha512-FNW1oLQpTJyqG5kkDg5ZsotvWgmBaC6jCHR7Ej0qUNep36Wl9tj2eZu7J5rP+uhXgHaLk+QQ3lqcw2vS5MX1IA==} + + '@socket.io/component-emitter@3.1.2': + resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==} + + '@solana-program/compute-budget@0.11.0': + resolution: {integrity: sha512-7f1ePqB/eURkTwTOO9TNIdUXZcyrZoX3Uy2hNo7cXMfNhPFWp9AVgIyRNBc2jf15sdUa9gNpW+PfP2iV8AYAaw==} + peerDependencies: + '@solana/kit': ^5.0 + + '@solana-program/system@0.8.1': + resolution: {integrity: sha512-71U9Mzdpw8HQtfgfJSL5xKZbLMRnza2Llsfk7gGnmg2waqK+o8MMH4YNma8xXS1UmOBptXIiNvoZ3p7cmOVktg==} + peerDependencies: + '@solana/kit': ^3.0 + + '@solana-program/token-2022@0.6.1': + resolution: {integrity: sha512-Ex02cruDMGfBMvZZCrggVR45vdQQSI/unHVpt/7HPt/IwFYB4eTlXtO8otYZyqV/ce5GqZ8S6uwyRf0zy6fdbA==} + peerDependencies: + '@solana/kit': ^5.0 + '@solana/sysvars': ^5.0 + + '@solana-program/token@0.6.0': + resolution: {integrity: sha512-omkZh4Tt9rre4wzWHNOhOEHyenXQku3xyc/UrKvShexA/Qlhza67q7uRwmwEDUs4QqoDBidSZPooOmepnA/jig==} + peerDependencies: + '@solana/kit': ^3.0 + + '@solana-program/token@0.9.0': + resolution: {integrity: sha512-vnZxndd4ED4Fc56sw93cWZ2djEeeOFxtaPS8SPf5+a+JZjKA/EnKqzbE1y04FuMhIVrLERQ8uR8H2h72eZzlsA==} + peerDependencies: + '@solana/kit': ^5.0 + + '@solana/accounts@3.0.3': + resolution: {integrity: sha512-KqlePrlZaHXfu8YQTCxN204ZuVm9o68CCcUr6l27MG2cuRUtEM1Ta0iR8JFkRUAEfZJC4Cu0ZDjK/v49loXjZQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/accounts@5.1.0': + resolution: {integrity: sha512-Q1KzykCrl/YjLUH2RXF8vPq65U/ehAV2SHZicPbZ0jvgQUU6X1+Eca+0ilxA9xH8srYn3YTVDyEs/LYdfbY/2A==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/addresses@3.0.3': + resolution: {integrity: sha512-AuMwKhJI89ANqiuJ/fawcwxNKkSeHH9CApZd2xelQQLS7X8uxAOovpcmEgiObQuiVP944s9ScGUT62Bdul9qYg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/addresses@5.1.0': + resolution: {integrity: sha512-X84qSZLgve9YeYsyxGI49WnfEre53tdFu4x9/4oULBgoj8d0A+P9VGLYzmRJ0YFYKRcZG7U4u3MQpI5uLZ1AsQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/assertions@3.0.3': + resolution: {integrity: sha512-2qspxdbWp2y62dfCIlqeWQr4g+hE8FYSSwcaP6itwMwGRb8393yDGCJfI/znuzJh6m/XVWhMHIgFgsBwnevCmg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/assertions@5.1.0': + resolution: {integrity: sha512-5But2wyxuvGXMIOnD0jBMQ9yq1QQF2LSK3IbIRSkAkXbD3DS6O2tRvKUHNhogd+BpkPyCGOQHBycezgnxmStlg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/buffer-layout@4.0.1': + resolution: {integrity: sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA==} + engines: {node: '>=5.10'} + + '@solana/codecs-core@2.3.0': + resolution: {integrity: sha512-oG+VZzN6YhBHIoSKgS5ESM9VIGzhWjEHEGNPSibiDTxFhsFWxNaz8LbMDPjBUE69r9wmdGLkrQ+wVPbnJcZPvw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/codecs-core@3.0.3': + resolution: {integrity: sha512-emKykJ3h1DmnDOY29Uv9eJXP8E/FHzvlUBJ6te+5EbKdFjj7vdlKYPfDxOI6iGdXTY+YC/ELtbNBh6QwF2uEDQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/codecs-core@5.1.0': + resolution: {integrity: sha512-vDwi03mxWeWCS5Il6BCdNdifYdOoHVz97YOmbWGIt45b77Ivu5NUYeSD2+ccl6fSw8eYQ6QaqqKXMjbSfsXv4g==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/codecs-data-structures@3.0.3': + resolution: {integrity: sha512-R15cLp8riJvToXziW8lP6AMSwsztGhEnwgyGmll32Mo0Yjq+hduW2/fJrA/TJs6tA/OgTzMQjlxgk009EqZHCw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/codecs-data-structures@5.1.0': + resolution: {integrity: sha512-ftAwL/jsurFrk9kFVhkTLdQ8fGZ8I0PcbVH+V1a0dIP2aKDofGePvK0XbwZE/ohizC9gEIZxyBX5IgRKk5PXyg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/codecs-numbers@2.3.0': + resolution: {integrity: sha512-jFvvwKJKffvG7Iz9dmN51OGB7JBcy2CJ6Xf3NqD/VP90xak66m/Lg48T01u5IQ/hc15mChVHiBm+HHuOFDUrQg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/codecs-numbers@3.0.3': + resolution: {integrity: sha512-pfXkH9J0glrM8qj6389GAn30+cJOxzXLR2FsPOHCUMXrqLhGjMMZAWhsQkpOQ37SGc/7EiQsT/gmyGC7gxHqJQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/codecs-numbers@5.1.0': + resolution: {integrity: sha512-Ea5/9yjDNOrDZcI40UGzzi6Aq1JNsmzM4m5pOk6Xb3JRZ0YdKOv/MwuCqb6jRgzZ7SQjHhkfGL43kHLJA++bOw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/codecs-strings@3.0.3': + resolution: {integrity: sha512-VHBXnnTVtcQ1j+7Vrz+qSYo38no+jiHRdGnhFspRXEHNJbllzwKqgBE7YN3qoIXH+MKxgJUcwO5KHmdzf8Wn2A==} + engines: {node: '>=20.18.0'} + peerDependencies: + fastestsmallesttextencoderdecoder: ^1.0.22 + typescript: '>=5.3.3' + + '@solana/codecs-strings@5.1.0': + resolution: {integrity: sha512-014xwl5T/3VnGW0gceizF47DUs5EURRtgGmbWIR5+Z32yxgQ6hT9Zl0atZbL268RHbUQ03/J8Ush1StQgy7sfQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + fastestsmallesttextencoderdecoder: ^1.0.22 + typescript: '>=5.3.3' + peerDependenciesMeta: + fastestsmallesttextencoderdecoder: + optional: true + + '@solana/codecs@3.0.3': + resolution: {integrity: sha512-GOHwTlIQsCoJx9Ryr6cEf0FHKAQ7pY4aO4xgncAftrv0lveTQ1rPP2inQ1QT0gJllsIa8nwbfXAADs9nNJxQDA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/codecs@5.1.0': + resolution: {integrity: sha512-krSuf/E2Sa/4oASZ/jb/5KGUG58m1/bQdLrKvBnoAFhYj7zZf+8V4UqHGTV5n2NCQfmMyORsg9n2saKjkUzo8w==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/errors@2.3.0': + resolution: {integrity: sha512-66RI9MAbwYV0UtP7kGcTBVLxJgUxoZGm8Fbc0ah+lGiAw17Gugco6+9GrJCV83VyF2mDWyYnYM9qdI3yjgpnaQ==} + engines: {node: '>=20.18.0'} + hasBin: true + peerDependencies: + typescript: '>=5.3.3' + + '@solana/errors@3.0.3': + resolution: {integrity: sha512-1l84xJlHNva6io62PcYfUamwWlc0eM95nHgCrKX0g0cLoC6D6QHYPCEbEVkR+C5UtP9JDgyQM8MFiv+Ei5tO9Q==} + engines: {node: '>=20.18.0'} + hasBin: true + peerDependencies: + typescript: '>=5.3.3' + + '@solana/errors@5.1.0': + resolution: {integrity: sha512-JlTyekErWa6Fdcwu1Hrh+jZxjM4YxyorGCFDRVZlmHZFkp5N00DWKcYnSGZrTF8E6ZZEP9pfS2XwM8y7p7HPww==} + engines: {node: '>=20.18.0'} + hasBin: true + peerDependencies: + typescript: '>=5.3.3' + + '@solana/fast-stable-stringify@3.0.3': + resolution: {integrity: sha512-ED0pxB6lSEYvg+vOd5hcuQrgzEDnOrURFgp1ZOY+lQhJkQU6xo+P829NcJZQVP1rdU2/YQPAKJKEseyfe9VMIw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/fast-stable-stringify@5.1.0': + resolution: {integrity: sha512-ACZo7cH/5EXsBmruw/0gU2/PXL2l4aET0YpL93H6QEaZwEAICFD8cLkj20nBcfLTf4srEiuKtwuSDeONTWIulw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/functional@3.0.3': + resolution: {integrity: sha512-2qX1kKANn8995vOOh5S9AmF4ItGZcfbny0w28Eqy8AFh+GMnSDN4gqpmV2LvxBI9HibXZptGH3RVOMk82h1Mpw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/functional@5.1.0': + resolution: {integrity: sha512-R6jacWU0Gr+j49lTDp+FSECBolqw2Gq7JlC22rI0JkcxJiiAlp3G80v6zAYq0FkHzxZbjyR6//JYUXSwliem5g==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/instruction-plans@3.0.3': + resolution: {integrity: sha512-eqoaPtWtmLTTpdvbt4BZF5H6FIlJtXi9H7qLOM1dLYonkOX2Ncezx5NDCZ9tMb2qxVMF4IocYsQnNSnMfjQF1w==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/instruction-plans@5.1.0': + resolution: {integrity: sha512-friMgHt0z5jQlCyyTDXfwAMYjCAagI7QYR+hLWB/BmvSuRpai0ddToWbWJoqrNRM312xZ+Oy/qjC3+Ftzi0DLA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/instructions@3.0.3': + resolution: {integrity: sha512-4csIi8YUDb5j/J+gDzmYtOvq7ZWLbCxj4t0xKn+fPrBk/FD2pK29KVT3Fu7j4Lh1/ojunQUP9X4NHwUexY3PnA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/instructions@5.1.0': + resolution: {integrity: sha512-fkwpUwwqk5K14T/kZDnCrfeR0kww49HBx+BK8xdSeJx+bt4QTwAHa9YeOkGhGrHEFVEJEUf8FKoxxTzZzJZtKQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/keys@3.0.3': + resolution: {integrity: sha512-tp8oK9tMadtSIc4vF4aXXWkPd4oU5XPW8nf28NgrGDWGt25fUHIydKjkf2hPtMt9i1WfRyQZ33B5P3dnsNqcPQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/keys@5.1.0': + resolution: {integrity: sha512-ma4zTTuSOmtTCvATHMfUGNTw0Vqah/6XPe1VmLc66ohwXMI3yqatX1FQPXgDZozr15SvLAesfs7/bgl2TRoe9w==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/kit@3.0.3': + resolution: {integrity: sha512-CEEhCDmkvztd1zbgADsEQhmj9GyWOOGeW1hZD+gtwbBSF5YN1uofS/pex5MIh/VIqKRj+A2UnYWI1V+9+q/lyQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/kit@5.1.0': + resolution: {integrity: sha512-oNQRzI0+mGWmXy05psO0J7r9Boy8PF7LH5H0Y9Jxvs10AbG4oSOBtyj20EccsRrr+jkqLw42fqb/4rNuASfvsA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/nominal-types@3.0.3': + resolution: {integrity: sha512-aZavCiexeUAoMHRQg4s1AHkH3wscbOb70diyfjhwZVgFz1uUsFez7csPp9tNFkNolnadVb2gky7yBk3IImQJ6A==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/nominal-types@5.1.0': + resolution: {integrity: sha512-+4Cm+SpK+D811i9giqv4Up93ZlmUcZfLDHkSH24F4in61+Y2TKA+XKuRtKhNytQMmqCfbvJZ9MHFaIeZw5g+Bg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/offchain-messages@5.1.0': + resolution: {integrity: sha512-6FUXjiIJprjWa7y/T4E3rUb3HKi3P5zpBweBEwDflEEJ/QlieWUw7xlGAOvZ1eF3Wi+6LfcrdtZOwIkuv6o9Sg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/options@3.0.3': + resolution: {integrity: sha512-jarsmnQ63RN0JPC5j9sgUat07NrL9PC71XU7pUItd6LOHtu4+wJMio3l5mT0DHVfkfbFLL6iI6+QmXSVhTNF3g==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/options@5.1.0': + resolution: {integrity: sha512-PqgfALd0yhK+QFaYIbRFTV6hBpiy5xwdu07zSw1RLoNvt1sg+MRsRFDk9R8ZdEdiM69PY/cKiClVSjpNzLLcJg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/programs@3.0.3': + resolution: {integrity: sha512-JZlVE3/AeSNDuH3aEzCZoDu8GTXkMpGXxf93zXLzbxfxhiQ/kHrReN4XE/JWZ/uGWbaFZGR5B3UtdN2QsoZL7w==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/programs@5.1.0': + resolution: {integrity: sha512-zAghXyRGixWNcarShlrnpjMD2115BZTF9JMLIcgkCYDOwjDPFIB/Y0hwDCH87N5uSjzlgkDpxKEL4ILewoZTRQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/promises@3.0.3': + resolution: {integrity: sha512-K+UflGBVxj30XQMHTylHHZJdKH5QG3oj5k2s42GrZ/Wbu72oapVJySMBgpK45+p90t8/LEqV6rRPyTXlet9J+Q==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/promises@5.1.0': + resolution: {integrity: sha512-LU9wwS1PvGc/It610dclfq+JCuUEZSIWjvaF0+sqMP7QCk12Uz7MK2m9TtvLcjTvvKTIrucglRZP6qKroWRqGg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc-api@3.0.3': + resolution: {integrity: sha512-Yym9/Ama62OY69rAZgbOCAy1QlqaWAyb0VlqFuwSaZV1pkFCCFSwWEJEsiN1n8pb2ZP+RtwNvmYixvWizx9yvA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc-api@5.1.0': + resolution: {integrity: sha512-eI1tY0i3gmih1C65gFECYbfPRpHEYqFp+9IKjpknZtYpQIe9BqBKSpfYpGiCAbKdN/TMadBNPOzdK15ewhkkvQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc-parsed-types@3.0.3': + resolution: {integrity: sha512-/koM05IM2fU91kYDQxXil3VBNlOfcP+gXE0js1sdGz8KonGuLsF61CiKB5xt6u1KEXhRyDdXYLjf63JarL4Ozg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc-parsed-types@5.1.0': + resolution: {integrity: sha512-ZJoXHNItALMNa1zmGrNnIh96RBlc9GpIqoaZkdE14mAQ7gWe7Oc0ejYavUeSCmcL0wZcvIFh50AsfVxrHr4+2Q==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc-spec-types@3.0.3': + resolution: {integrity: sha512-A6Jt8SRRetnN3CeGAvGJxigA9zYRslGgWcSjueAZGvPX+MesFxEUjSWZCfl+FogVFvwkqfkgQZQbPAGZQFJQ6Q==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc-spec-types@5.1.0': + resolution: {integrity: sha512-B8/WyjmHpC34vXtAmTpZyPwRCm7WwoSkmjBcBouaaY1uilJ9+Wp2nptbq2cJyWairOoMSoI7v5kvvnrJuquq4Q==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc-spec@3.0.3': + resolution: {integrity: sha512-MZn5/8BebB6MQ4Gstw6zyfWsFAZYAyLzMK+AUf/rSfT8tPmWiJ/mcxnxqOXvFup/l6D67U8pyGpIoFqwCeZqqA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc-spec@5.1.0': + resolution: {integrity: sha512-y8B6fUWA1EBKXUsNo6b9EiFcQPsaJREPLlcIDbo4b6TucQNwvl7FHfpf1VHJL64SkI/WE69i2WEkiOJYjmLO0A==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc-subscriptions-api@3.0.3': + resolution: {integrity: sha512-MGgVK3PUS15qsjuhimpzGZrKD/CTTvS0mAlQ0Jw84zsr1RJVdQJK/F0igu07BVd172eTZL8d90NoAQ3dahW5pA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc-subscriptions-api@5.1.0': + resolution: {integrity: sha512-84e2AsgqAGiVloW3G4RzpHPkInknu3rEuFPut2/69eq3Ab97TiTz2s5kc9gJpprtGM+xbgnIfeuGqr5F+2bXQA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc-subscriptions-channel-websocket@3.0.3': + resolution: {integrity: sha512-zUzUlb8Cwnw+SHlsLrSqyBRtOJKGc+FvSNJo/vWAkLShoV0wUDMPv7VvhTngJx3B/3ANfrOZ4i08i9QfYPAvpQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + ws: ^8.18.0 + + '@solana/rpc-subscriptions-channel-websocket@5.1.0': + resolution: {integrity: sha512-FzAEmHzXtlckNn7T/1dzDS7r5HmekYPstrtZKjDcVxuGMVBUkZTnb69t7EJvKNuKw1wYZEUd0EEegtC2K/9dZA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + ws: ^8.18.0 + peerDependenciesMeta: + ws: + optional: true + + '@solana/rpc-subscriptions-spec@3.0.3': + resolution: {integrity: sha512-9KpQ32OBJWS85mn6q3gkM0AjQe1LKYlMU7gpJRrla/lvXxNLhI95tz5K6StctpUreVmRWTVkNamHE69uUQyY8A==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc-subscriptions-spec@5.1.0': + resolution: {integrity: sha512-ORfjKtainnYisql6z4YsXByVwY8/rWsedVWn5oe/V7Og9LyetTM7hwJ8FbUdRDZwyLlUrI0cEE1aG+3ma/8tPw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc-subscriptions@3.0.3': + resolution: {integrity: sha512-LRvz6NaqvtsYFd32KwZ+rwYQ9XCs+DWjV8BvBLsJpt9/NWSuHf/7Sy/vvP6qtKxut692H/TMvHnC4iulg0WmiQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc-subscriptions@5.1.0': + resolution: {integrity: sha512-u/mafVzBbdqvYDD7x/98T5/5xk4Bl2C/90TaHiKx7FmutVC/H4QsritPTY0v9JG1dOVWbgIfUgfZ0C0DPkiYnA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc-transformers@3.0.3': + resolution: {integrity: sha512-lzdaZM/dG3s19Tsk4mkJA5JBoS1eX9DnD7z62gkDwrwJDkDBzkAJT9aLcsYFfTmwTfIp6uU2UPgGYc97i1wezw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc-transformers@5.1.0': + resolution: {integrity: sha512-6v93xi/ewGS/xEiSktNQ0bh0Uiv1/q9nR5oiFMn3BiAJRC+FdMRMxCjp6H+/Tua7wdhpClaPKrZYBQHoIp59tw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc-transport-http@3.0.3': + resolution: {integrity: sha512-bIXFwr2LR5A97Z46dI661MJPbHnPfcShBjFzOS/8Rnr8P4ho3j/9EUtjDrsqoxGJT3SLWj5OlyXAlaDAvVTOUQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc-transport-http@5.1.0': + resolution: {integrity: sha512-XoGX+2n/iXzoGb3Xrltbx8avnzp15vCfCGXuZpQWFL+xUg3P4CGl217XyDGjS5VxuUml+f/30xzWl18RaAIEcw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc-types@3.0.3': + resolution: {integrity: sha512-petWQ5xSny9UfmC3Qp2owyhNU0w9SyBww4+v7tSVyXMcCC9v6j/XsqTeimH1S0qQUllnv0/FY83ohFaxofmZ6Q==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc-types@5.1.0': + resolution: {integrity: sha512-Rnpt5BuHQvnULPNXUC/yRqB+7iPbon95CSCeyRvPj5tJ4fx2JibvX3s/UEoud5vC+kRjPi/R0BGJ8XFvd3eDWg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc@3.0.3': + resolution: {integrity: sha512-3oukAaLK78GegkKcm6iNmRnO4mFeNz+BMvA8T56oizoBNKiRVEq/6DFzVX/LkmZ+wvD601pAB3uCdrTPcC0YKQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc@5.1.0': + resolution: {integrity: sha512-j+ByLxFCoHWw9TnsGzkAVMFUfBDIUE53nIosJAYEsERpImD2mjwc33uDE6YXLKoaKRoYO4tc7IUzkKY1fQp/CA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/signers@3.0.3': + resolution: {integrity: sha512-UwCd/uPYTZiwd283JKVyOWLLN5sIgMBqGDyUmNU3vo9hcmXKv5ZGm/9TvwMY2z35sXWuIOcj7etxJ8OoWc/ObQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/signers@5.1.0': + resolution: {integrity: sha512-B8xO0SGN1ZWYfJROL+da3id279qNbXbXoqud+AuT5gur51RrS4YhNkTQ6khVbGtAOpPMAhkoZN0jnfCC1r33jQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/subscribable@3.0.3': + resolution: {integrity: sha512-FJ27LKGHLQ5GGttPvTOLQDLrrOZEgvaJhB7yYaHAhPk25+p+erBaQpjePhfkMyUbL1FQbxn1SUJmS6jUuaPjlQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/subscribable@5.1.0': + resolution: {integrity: sha512-OeW5AJwKzHh18+PIPtghuuPJTmEep2Mhb3Lsrq4alas4fibmMGkr39z1HXxVF6l6e2lu/YGhHIDtuhouWmY7ow==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/sysvars@3.0.3': + resolution: {integrity: sha512-GnHew+QeKCs2f9ow+20swEJMH4mDfJA/QhtPgOPTYQx/z69J4IieYJ7fZenSHnA//lJ45fVdNdmy1trypvPLBQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/sysvars@5.1.0': + resolution: {integrity: sha512-FJ9YIsLTAaajnOrYEYn54znstXJsvKndRhyCrlyiAEN1IXHw5HtZHploLF3ZZ78b7YU3uv3tFJMziXFBwPOn4Q==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/transaction-confirmation@3.0.3': + resolution: {integrity: sha512-dXx0OLtR95LMuARgi2dDQlL1QYmk56DOou5q9wKymmeV3JTvfDExeWXnOgjRBBq/dEfj4ugN1aZuTaS18UirFw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/transaction-confirmation@5.1.0': + resolution: {integrity: sha512-6HnL0uH8tWZXJVuaoeTbCQp/FS11Bsc4GSlq+k0N21GdhTbFuqBhsxlAYWbzPWs9+/kYRGHqqXvBPCReWxT7BA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/transaction-messages@3.0.3': + resolution: {integrity: sha512-s+6NWRnBhnnjFWV4x2tzBzoWa6e5LiIxIvJlWwVQBFkc8fMGY04w7jkFh0PM08t/QFKeXBEWkyBDa/TFYdkWug==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/transaction-messages@5.1.0': + resolution: {integrity: sha512-9rNV2YJhd85WIMvnwa/vUY4xUw3ZTU17jP1KDo/fFZWk55a0ov0ATJJPyC5HAR1i6hT1cmJzGH/UHhnD9m/Q3w==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/transactions@3.0.3': + resolution: {integrity: sha512-iMX+n9j4ON7H1nKlWEbMqMOpKYC6yVGxKKmWHT1KdLRG7v+03I4DnDeFoI+Zmw56FA+7Bbne8jwwX60Q1vk/MQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/transactions@5.1.0': + resolution: {integrity: sha512-06JwSPtz+38ozNgpysAXS2eTMPQCufIisXB6K88X8J4GF8ziqs4nkq0BpXAXn+MpZTkuMt+JeW2RxP3HKhXe5g==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/wallet-standard-features@1.3.0': + resolution: {integrity: sha512-ZhpZtD+4VArf6RPitsVExvgkF+nGghd1rzPjd97GmBximpnt1rsUxMOEyoIEuH3XBxPyNB6Us7ha7RHWQR+abg==} + engines: {node: '>=16'} + + '@solana/web3.js@1.98.4': + resolution: {integrity: sha512-vv9lfnvjUsRiq//+j5pBdXig0IQdtzA0BRZ3bXEP4KaIyF1CcaydWqgyzQgfZMNIsWNWmG+AUHwPy4AHOD6gpw==} + + '@swc/helpers@0.5.17': + resolution: {integrity: sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==} + + '@tailwindcss/node@4.1.18': + resolution: {integrity: sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==} + + '@tailwindcss/oxide-android-arm64@4.1.18': + resolution: {integrity: sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.1.18': + resolution: {integrity: sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.1.18': + resolution: {integrity: sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.1.18': + resolution: {integrity: sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18': + resolution: {integrity: sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.18': + resolution: {integrity: sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-musl@4.1.18': + resolution: {integrity: sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-gnu@4.1.18': + resolution: {integrity: sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-musl@4.1.18': + resolution: {integrity: sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-wasm32-wasi@4.1.18': + resolution: {integrity: sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.18': + resolution: {integrity: sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.1.18': + resolution: {integrity: sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.1.18': + resolution: {integrity: sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A==} + engines: {node: '>= 10'} + + '@tailwindcss/vite@4.1.18': + resolution: {integrity: sha512-jVA+/UpKL1vRLg6Hkao5jldawNmRo7mQYrZtNHMIVpLfLhDml5nMRUo/8MwoX2vNXvnaXNNMedrMfMugAVX1nA==} + peerDependencies: + vite: ^5.2.0 || ^6 || ^7 + + '@tanstack/query-core@5.90.12': + resolution: {integrity: sha512-T1/8t5DhV/SisWjDnaiU2drl6ySvsHj1bHBCWNXd+/T+Hh1cf6JodyEYMd5sgwm+b/mETT4EV3H+zCVczCU5hg==} + + '@tanstack/react-query@5.90.12': + resolution: {integrity: sha512-graRZspg7EoEaw0a8faiUASCyJrqjKPdqJ9EwuDRUF9mEYJ1YPczI9H+/agJ0mOJkPCJDk0lsz5QTrLZ/jQ2rg==} + peerDependencies: + react: ^18 || ^19 + + '@tanstack/react-virtual@3.13.13': + resolution: {integrity: sha512-4o6oPMDvQv+9gMi8rE6gWmsOjtUZUYIJHv7EB+GblyYdi8U6OqLl8rhHWIUZSL1dUU2dPwTdTgybCKf9EjIrQg==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + '@tanstack/virtual-core@3.13.13': + resolution: {integrity: sha512-uQFoSdKKf5S8k51W5t7b2qpfkyIbdHMzAn+AMQvHPxKUPeo1SsGaA4JRISQT87jm28b7z8OEqPcg1IOZagQHcA==} + + '@tybys/wasm-util@0.10.1': + resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + + '@types/babel__generator@7.27.0': + resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + + '@types/babel__traverse@7.28.0': + resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + + '@types/connect@3.4.38': + resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} + + '@types/debug@4.1.12': + resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/lodash@4.17.21': + resolution: {integrity: sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ==} + + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + + '@types/node@12.20.55': + resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} + + '@types/node@25.0.3': + resolution: {integrity: sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA==} + + '@types/react-dom@19.2.3': + resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} + peerDependencies: + '@types/react': ^19.2.0 + + '@types/react@19.2.7': + resolution: {integrity: sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==} + + '@types/stylis@4.2.5': + resolution: {integrity: sha512-1Xve+NMN7FWjY14vLoY5tL3BVEQ/n42YLwaqJIPYhotZ9uBHt87VceMwWQpzmdEt2TNXIorIFG+YeCUUW7RInw==} + + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + + '@types/uuid@8.3.4': + resolution: {integrity: sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==} + + '@types/ws@7.4.7': + resolution: {integrity: sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==} + + '@types/ws@8.18.1': + resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} + + '@typescript-eslint/eslint-plugin@8.50.1': + resolution: {integrity: sha512-PKhLGDq3JAg0Jk/aK890knnqduuI/Qj+udH7wCf0217IGi4gt+acgCyPVe79qoT+qKUvHMDQkwJeKW9fwl8Cyw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.50.1 + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/parser@8.50.1': + resolution: {integrity: sha512-hM5faZwg7aVNa819m/5r7D0h0c9yC4DUlWAOvHAtISdFTc8xB86VmX5Xqabrama3wIPJ/q9RbGS1worb6JfnMg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/project-service@8.50.1': + resolution: {integrity: sha512-E1ur1MCVf+YiP89+o4Les/oBAVzmSbeRB0MQLfSlYtbWU17HPxZ6Bhs5iYmKZRALvEuBoXIZMOIRRc/P++Ortg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/scope-manager@8.50.1': + resolution: {integrity: sha512-mfRx06Myt3T4vuoHaKi8ZWNTPdzKPNBhiblze5N50//TSHOAQQevl/aolqA/BcqqbJ88GUnLqjjcBc8EWdBcVw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/tsconfig-utils@8.50.1': + resolution: {integrity: sha512-ooHmotT/lCWLXi55G4mvaUF60aJa012QzvLK0Y+Mp4WdSt17QhMhWOaBWeGTFVkb2gDgBe19Cxy1elPXylslDw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/type-utils@8.50.1': + resolution: {integrity: sha512-7J3bf022QZE42tYMO6SL+6lTPKFk/WphhRPe9Tw/el+cEwzLz1Jjz2PX3GtGQVxooLDKeMVmMt7fWpYRdG5Etg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/types@8.50.1': + resolution: {integrity: sha512-v5lFIS2feTkNyMhd7AucE/9j/4V9v5iIbpVRncjk/K0sQ6Sb+Np9fgYS/63n6nwqahHQvbmujeBL7mp07Q9mlA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.50.1': + resolution: {integrity: sha512-woHPdW+0gj53aM+cxchymJCrh0cyS7BTIdcDxWUNsclr9VDkOSbqC13juHzxOmQ22dDkMZEpZB+3X1WpUvzgVQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/utils@8.50.1': + resolution: {integrity: sha512-lCLp8H1T9T7gPbEuJSnHwnSuO9mDf8mfK/Nion5mZmiEaQD9sWf9W4dfeFqRyqRjF06/kBuTmAqcs9sewM2NbQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/visitor-keys@8.50.1': + resolution: {integrity: sha512-IrDKrw7pCRUR94zeuCSUWQ+w8JEf5ZX5jl/e6AHGSLi1/zIr0lgutfn/7JpfCey+urpgQEdrZVYzCaVVKiTwhQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@vitejs/plugin-react@5.1.2': + resolution: {integrity: sha512-EcA07pHJouywpzsoTUqNh5NwGayl2PPVEJKUSinGGSxFGYn+shYbqMGBg6FXDqgXum9Ou/ecb+411ssw8HImJQ==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + + '@wagmi/connectors@6.2.0': + resolution: {integrity: sha512-2NfkbqhNWdjfibb4abRMrn7u6rPjEGolMfApXss6HCDVt9AW2oVC6k8Q5FouzpJezElxLJSagWz9FW1zaRlanA==} + peerDependencies: + '@wagmi/core': 2.22.1 + typescript: '>=5.0.4' + viem: 2.x + peerDependenciesMeta: + typescript: + optional: true + + '@wagmi/connectors@7.0.3': + resolution: {integrity: sha512-LJJ4ozoX6sFcm5109B2kW42Amad6urpzyySDupA43CBw9K/IBrgJ5aPSuPbOip6AxJ0BL6MKz2vqFIN2LFV4hA==} + peerDependencies: + '@base-org/account': ~2.4.0 + '@coinbase/wallet-sdk': ~4.3.6 + '@gemini-wallet/core': ~0.3.1 + '@metamask/sdk': ~0.33.1 + '@safe-global/safe-apps-provider': ~0.18.6 + '@safe-global/safe-apps-sdk': ~9.1.0 + '@wagmi/core': 3.0.1 + '@walletconnect/ethereum-provider': ~2.21.1 + porto: ~0.2.35 + typescript: '>=5.7.3' + viem: 2.x + peerDependenciesMeta: + '@base-org/account': + optional: true + '@coinbase/wallet-sdk': + optional: true + '@gemini-wallet/core': + optional: true + '@metamask/sdk': + optional: true + '@safe-global/safe-apps-provider': + optional: true + '@safe-global/safe-apps-sdk': + optional: true + '@walletconnect/ethereum-provider': + optional: true + porto: + optional: true + typescript: + optional: true + + '@wagmi/core@2.22.1': + resolution: {integrity: sha512-cG/xwQWsBEcKgRTkQVhH29cbpbs/TdcUJVFXCyri3ZknxhMyGv0YEjTcrNpRgt2SaswL1KrvslSNYKKo+5YEAg==} + peerDependencies: + '@tanstack/query-core': '>=5.0.0' + typescript: '>=5.0.4' + viem: 2.x + peerDependenciesMeta: + '@tanstack/query-core': + optional: true + typescript: + optional: true + + '@wagmi/core@3.0.1': + resolution: {integrity: sha512-i+wNyvPPxJbaaDeIDflqJyCymrMuelcZr/XvVNC2/aj7tJkEQmsAYguaozpImr39RpMLt8NFQBW6pW/n3WDZ1A==} + peerDependencies: + '@tanstack/query-core': '>=5.0.0' + typescript: '>=5.7.3' + viem: 2.x + peerDependenciesMeta: + '@tanstack/query-core': + optional: true + typescript: + optional: true + + '@wallet-standard/app@1.1.0': + resolution: {integrity: sha512-3CijvrO9utx598kjr45hTbbeeykQrQfKmSnxeWOgU25TOEpvcipD/bYDQWIqUv1Oc6KK4YStokSMu/FBNecGUQ==} + engines: {node: '>=16'} + + '@wallet-standard/base@1.1.0': + resolution: {integrity: sha512-DJDQhjKmSNVLKWItoKThJS+CsJQjR9AOBOirBVT1F9YpRyC9oYHE+ZnSf8y8bxUphtKqdQMPVQ2mHohYdRvDVQ==} + engines: {node: '>=16'} + + '@wallet-standard/features@1.1.0': + resolution: {integrity: sha512-hiEivWNztx73s+7iLxsuD1sOJ28xtRix58W7Xnz4XzzA/pF0+aicnWgjOdA10doVDEDZdUuZCIIqG96SFNlDUg==} + engines: {node: '>=16'} + + '@wallet-standard/wallet@1.1.0': + resolution: {integrity: sha512-Gt8TnSlDZpAl+RWOOAB/kuvC7RpcdWAlFbHNoi4gsXsfaWa1QCT6LBcfIYTPdOZC9OVZUDwqGuGAcqZejDmHjg==} + engines: {node: '>=16'} + + '@walletconnect/core@2.21.0': + resolution: {integrity: sha512-o6R7Ua4myxR8aRUAJ1z3gT9nM+jd2B2mfamu6arzy1Cc6vi10fIwFWb6vg3bC8xJ6o9H3n/cN5TOW3aA9Y1XVw==} + engines: {node: '>=18'} + + '@walletconnect/core@2.21.1': + resolution: {integrity: sha512-Tp4MHJYcdWD846PH//2r+Mu4wz1/ZU/fr9av1UWFiaYQ2t2TPLDiZxjLw54AAEpMqlEHemwCgiRiAmjR1NDdTQ==} + engines: {node: '>=18'} + + '@walletconnect/core@2.21.9': + resolution: {integrity: sha512-SlSknLvbO4i9Y4y8zU0zeCuJv1klQIUX3HRSBs1BaYvQKVVkrdiWPgRj4jcrL2wEOINa9NXw6HXp6x5XCXOolA==} + engines: {node: '>=18.20.8'} + + '@walletconnect/core@2.22.4': + resolution: {integrity: sha512-ZQnyDDpqDPAk5lyLV19BRccQ3wwK3LmAwibuIv3X+44aT/dOs2kQGu9pla3iW2LgZ5qRMYvgvvfr5g3WlDGceQ==} + engines: {node: '>=18.20.8'} + + '@walletconnect/environment@1.0.1': + resolution: {integrity: sha512-T426LLZtHj8e8rYnKfzsw1aG6+M0BT1ZxayMdv/p8yM0MU+eJDISqNY3/bccxRr4LrF9csq02Rhqt08Ibl0VRg==} + + '@walletconnect/ethereum-provider@2.21.1': + resolution: {integrity: sha512-SSlIG6QEVxClgl1s0LMk4xr2wg4eT3Zn/Hb81IocyqNSGfXpjtawWxKxiC5/9Z95f1INyBD6MctJbL/R1oBwIw==} + deprecated: 'Reliability and performance improvements. See: https://github.com/WalletConnect/walletconnect-monorepo/releases' + + '@walletconnect/ethereum-provider@2.22.4': + resolution: {integrity: sha512-qhBxU95nlndiKGz8lO8z9JlsA4Ai8i1via4VWut2fXsW1fkl6qXG9mYhDRFsbavuynUe3dQ+QLjBVDaaNkcKCA==} + + '@walletconnect/events@1.0.1': + resolution: {integrity: sha512-NPTqaoi0oPBVNuLv7qPaJazmGHs5JGyO8eEAk5VGKmJzDR7AHzD4k6ilox5kxk1iwiOnFopBOOMLs86Oa76HpQ==} + + '@walletconnect/heartbeat@1.2.2': + resolution: {integrity: sha512-uASiRmC5MwhuRuf05vq4AT48Pq8RMi876zV8rr8cV969uTOzWdB/k+Lj5yI2PBtB1bGQisGen7MM1GcZlQTBXw==} + + '@walletconnect/jsonrpc-http-connection@1.0.8': + resolution: {integrity: sha512-+B7cRuaxijLeFDJUq5hAzNyef3e3tBDIxyaCNmFtjwnod5AGis3RToNqzFU33vpVcxFhofkpE7Cx+5MYejbMGw==} + + '@walletconnect/jsonrpc-provider@1.0.14': + resolution: {integrity: sha512-rtsNY1XqHvWj0EtITNeuf8PHMvlCLiS3EjQL+WOkxEOA4KPxsohFnBDeyPYiNm4ZvkQdLnece36opYidmtbmow==} + + '@walletconnect/jsonrpc-types@1.0.4': + resolution: {integrity: sha512-P6679fG/M+wuWg9TY8mh6xFSdYnFyFjwFelxyISxMDrlbXokorEVXYOxiqEbrU3x1BmBoCAJJ+vtEaEoMlpCBQ==} + + '@walletconnect/jsonrpc-utils@1.0.8': + resolution: {integrity: sha512-vdeb03bD8VzJUL6ZtzRYsFMq1eZQcM3EAzT0a3st59dyLfJ0wq+tKMpmGH7HlB7waD858UWgfIcudbPFsbzVdw==} + + '@walletconnect/jsonrpc-ws-connection@1.0.16': + resolution: {integrity: sha512-G81JmsMqh5nJheE1mPst1W0WfVv0SG3N7JggwLLGnI7iuDZJq8cRJvQwLGKHn5H1WTW7DEPCo00zz5w62AbL3Q==} + + '@walletconnect/keyvaluestorage@1.1.1': + resolution: {integrity: sha512-V7ZQq2+mSxAq7MrRqDxanTzu2RcElfK1PfNYiaVnJgJ7Q7G7hTVwF8voIBx92qsRyGHZihrwNPHuZd1aKkd0rA==} + peerDependencies: + '@react-native-async-storage/async-storage': 1.x + peerDependenciesMeta: + '@react-native-async-storage/async-storage': + optional: true + + '@walletconnect/logger@2.1.2': + resolution: {integrity: sha512-aAb28I3S6pYXZHQm5ESB+V6rDqIYfsnHaQyzFbwUUBFY4H0OXx/YtTl8lvhUNhMMfb9UxbwEBS253TlXUYJWSw==} + + '@walletconnect/logger@3.0.0': + resolution: {integrity: sha512-DDktPBFdmt5d7U3sbp4e3fQHNS1b6amsR8FmtOnt6L2SnV7VfcZr8VmAGL12zetAR+4fndegbREmX0P8Mw6eDg==} + + '@walletconnect/relay-api@1.0.11': + resolution: {integrity: sha512-tLPErkze/HmC9aCmdZOhtVmYZq1wKfWTJtygQHoWtgg722Jd4homo54Cs4ak2RUFUZIGO2RsOpIcWipaua5D5Q==} + + '@walletconnect/relay-auth@1.1.0': + resolution: {integrity: sha512-qFw+a9uRz26jRCDgL7Q5TA9qYIgcNY8jpJzI1zAWNZ8i7mQjaijRnWFKsCHAU9CyGjvt6RKrRXyFtFOpWTVmCQ==} + + '@walletconnect/safe-json@1.0.2': + resolution: {integrity: sha512-Ogb7I27kZ3LPC3ibn8ldyUr5544t3/STow9+lzz7Sfo808YD7SBWk7SAsdBFlYgP2zDRy2hS3sKRcuSRM0OTmA==} + + '@walletconnect/sign-client@2.21.0': + resolution: {integrity: sha512-z7h+PeLa5Au2R591d/8ZlziE0stJvdzP9jNFzFolf2RG/OiXulgFKum8PrIyXy+Rg2q95U9nRVUF9fWcn78yBA==} + deprecated: 'Reliability and performance improvements. See: https://github.com/WalletConnect/walletconnect-monorepo/releases' + + '@walletconnect/sign-client@2.21.1': + resolution: {integrity: sha512-QaXzmPsMnKGV6tc4UcdnQVNOz4zyXgarvdIQibJ4L3EmLat73r5ZVl4c0cCOcoaV7rgM9Wbphgu5E/7jNcd3Zg==} + deprecated: 'Reliability and performance improvements. See: https://github.com/WalletConnect/walletconnect-monorepo/releases' + + '@walletconnect/sign-client@2.21.9': + resolution: {integrity: sha512-EKLDS97o1rk/0XilD0nQdSR9SNgRsVoIK5M5HpS9sDTvHPv2EF5pIqu6Xr2vLsKcQ0KnCx+D5bnpav8Yh4NVZg==} + + '@walletconnect/sign-client@2.22.4': + resolution: {integrity: sha512-la+sol0KL33Fyx5DRlupHREIv8wA6W33bRfuLAfLm8pINRTT06j9rz0IHIqJihiALebFxVZNYzJnF65PhV0q3g==} + + '@walletconnect/time@1.0.2': + resolution: {integrity: sha512-uzdd9woDcJ1AaBZRhqy5rNC9laqWGErfc4dxA9a87mPdKOgWMD85mcFo9dIYIts/Jwocfwn07EC6EzclKubk/g==} + + '@walletconnect/types@2.21.0': + resolution: {integrity: sha512-ll+9upzqt95ZBWcfkOszXZkfnpbJJ2CmxMfGgE5GmhdxxxCcO5bGhXkI+x8OpiS555RJ/v/sXJYMSOLkmu4fFw==} + + '@walletconnect/types@2.21.1': + resolution: {integrity: sha512-UeefNadqP6IyfwWC1Yi7ux+ljbP2R66PLfDrDm8izmvlPmYlqRerJWJvYO4t0Vvr9wrG4Ko7E0c4M7FaPKT/sQ==} + + '@walletconnect/types@2.21.9': + resolution: {integrity: sha512-+82TRNX3lGRO96WyLISaBs/FkLts7y4hVgmOI4we84I7XdBu1xsjgiJj0JwYXnurz+X94lTqzOkzPps+wadWKw==} + + '@walletconnect/types@2.22.4': + resolution: {integrity: sha512-KJdiS9ezXzx1uASanldYaaenDwb42VOQ6Rj86H7FRwfYddhNnYnyEaDjDKOdToGRGcpt5Uzom6qYUOnrWEbp5g==} + + '@walletconnect/universal-provider@2.21.0': + resolution: {integrity: sha512-mtUQvewt+X0VBQay/xOJBvxsB3Xsm1lTwFjZ6WUwSOTR1X+FNb71hSApnV5kbsdDIpYPXeQUbGt2se1n5E5UBg==} + deprecated: 'Reliability and performance improvements. See: https://github.com/WalletConnect/walletconnect-monorepo/releases' + + '@walletconnect/universal-provider@2.21.1': + resolution: {integrity: sha512-Wjx9G8gUHVMnYfxtasC9poGm8QMiPCpXpbbLFT+iPoQskDDly8BwueWnqKs4Mx2SdIAWAwuXeZ5ojk5qQOxJJg==} + deprecated: 'Reliability and performance improvements. See: https://github.com/WalletConnect/walletconnect-monorepo/releases' + + '@walletconnect/universal-provider@2.21.9': + resolution: {integrity: sha512-dVA9DWSz9jYe37FW5GSRV5zlY9E7rX1kktcDGI7i1/9oG/z9Pk5UKp5r/DFys4Zjml9wZc46R/jlEgeBXTT06A==} + + '@walletconnect/universal-provider@2.22.4': + resolution: {integrity: sha512-TF2RNX13qxa0rrBAhVDs5+C2G8CHX7L0PH5hF2uyQHdGyxZ3pFbXf8rxmeW1yKlB76FSbW80XXNrUes6eK/xHg==} + + '@walletconnect/utils@2.21.0': + resolution: {integrity: sha512-zfHLiUoBrQ8rP57HTPXW7rQMnYxYI4gT9yTACxVW6LhIFROTF6/ytm5SKNoIvi4a5nX5dfXG4D9XwQUCu8Ilig==} + + '@walletconnect/utils@2.21.1': + resolution: {integrity: sha512-VPZvTcrNQCkbGOjFRbC24mm/pzbRMUq2DSQoiHlhh0X1U7ZhuIrzVtAoKsrzu6rqjz0EEtGxCr3K1TGRqDG4NA==} + + '@walletconnect/utils@2.21.9': + resolution: {integrity: sha512-FHagysDvp7yQl+74veIeuqwZZnMiTyTW3Lw0NXsbIKnlmlSQu5pma+4EnRD/CnSzbN6PV39k2t1KBaaZ4PjDgg==} + + '@walletconnect/utils@2.22.4': + resolution: {integrity: sha512-coAPrNiTiD+snpiXQyXakMVeYcddqVqII7aLU39TeILdPoXeNPc2MAja+MF7cKNM/PA3tespljvvxck/oTm4+Q==} + + '@walletconnect/window-getters@1.0.1': + resolution: {integrity: sha512-vHp+HqzGxORPAN8gY03qnbTMnhqIwjeRJNOMOAzePRg4xVEEE2WvYsI9G2NMjOknA8hnuYbU3/hwLcKbjhc8+Q==} + + '@walletconnect/window-metadata@1.0.1': + resolution: {integrity: sha512-9koTqyGrM2cqFRW517BPY/iEtUDx2r1+Pwwu5m7sJ7ka79wi3EyqhqcICk/yDmv6jAS1rjKgTKXlEhanYjijcA==} + + abitype@1.0.6: + resolution: {integrity: sha512-MMSqYh4+C/aVqI2RQaWqbvI4Kxo5cQV40WQ4QFtDnNzCkqChm8MuENhElmynZlO0qUy/ObkEUaXtKqYnx1Kp3A==} + peerDependencies: + typescript: '>=5.0.4' + zod: ^3 >=3.22.0 + peerDependenciesMeta: + typescript: + optional: true + zod: + optional: true + + abitype@1.0.8: + resolution: {integrity: sha512-ZeiI6h3GnW06uYDLx0etQtX/p8E24UaHHBj57RSjK7YBFe7iuVn07EDpOeP451D06sF27VOz9JJPlIKJmXgkEg==} + peerDependencies: + typescript: '>=5.0.4' + zod: ^3 >=3.22.0 + peerDependenciesMeta: + typescript: + optional: true + zod: + optional: true + + abitype@1.2.3: + resolution: {integrity: sha512-Ofer5QUnuUdTFsBRwARMoWKOH1ND5ehwYhJ3OJ/BQO+StkwQjHw0XyVh4vDttzHB7QOFhPHa/o413PJ82gU/Tg==} + peerDependencies: + typescript: '>=5.0.4' + zod: ^3.22.0 || ^4.0.0 + peerDependenciesMeta: + typescript: + optional: true + zod: + optional: true + + abort-controller@3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + engines: {node: '>=0.4.0'} + hasBin: true + + agentkeepalive@4.6.0: + resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==} + engines: {node: '>= 8.0.0'} + + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + async-mutex@0.2.6: + resolution: {integrity: sha512-Hs4R+4SPgamu6rSGW8C7cV9gaWUKEHykfzCCvIRuaVv636Ju10ZdeUbvb4TBEW0INuq2DHZqXbK4Nd3yG4RaRw==} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + atomic-sleep@1.0.0: + resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} + engines: {node: '>=8.0.0'} + + available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + + axios-retry@4.5.0: + resolution: {integrity: sha512-aR99oXhpEDGo0UuAlYcn2iGRds30k366Zfa05XWScR9QaQD4JYiP3/1Qt1u7YlefUOK+cn0CcwoL1oefavQUlQ==} + peerDependencies: + axios: 0.x || 1.x + + axios@1.13.2: + resolution: {integrity: sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + base-x@3.0.11: + resolution: {integrity: sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==} + + base-x@5.0.1: + resolution: {integrity: sha512-M7uio8Zt++eg3jPj+rHMfCC+IuygQHHCOU+IYsVtik6FWjuYpVt/+MRKcgsAMHh8mMFAwnB+Bs+mTrFiXjMzKg==} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + baseline-browser-mapping@2.9.11: + resolution: {integrity: sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ==} + hasBin: true + + big.js@6.2.2: + resolution: {integrity: sha512-y/ie+Faknx7sZA5MfGA2xKlu0GDv8RWrXGsmlteyJQ2lvoKv9GBK/fpRMc2qlSoBAgNxrixICFCBefIq8WCQpQ==} + + blakejs@1.2.1: + resolution: {integrity: sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==} + + bn.js@5.2.2: + resolution: {integrity: sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==} + + borsh@0.7.0: + resolution: {integrity: sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==} + + bowser@2.13.1: + resolution: {integrity: sha512-OHawaAbjwx6rqICCKgSG0SAnT05bzd7ppyKLVUITZpANBaaMFBAsaNkto3LoQ31tyFP5kNujE8Cdx85G9VzOkw==} + + brace-expansion@1.1.12: + resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} + + brace-expansion@2.0.2: + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + + browserslist@4.28.1: + resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + bs58@4.0.1: + resolution: {integrity: sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==} + + bs58@6.0.0: + resolution: {integrity: sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==} + + buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + + bufferutil@4.1.0: + resolution: {integrity: sha512-ZMANVnAixE6AWWnPzlW2KpUrxhm9woycYvPOo67jWHyFowASTEd9s+QN1EIMsSDtwhIxN4sWE1jotpuDUIgyIw==} + engines: {node: '>=6.14.2'} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bind@1.0.8: + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + 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'} + + camelize@1.0.1: + resolution: {integrity: sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==} + + caniuse-lite@1.0.30001761: + resolution: {integrity: sha512-JF9ptu1vP2coz98+5051jZ4PwQgd2ni8A+gYSN7EA7dPKIMf0pDlSUxhdmVOaV3/fYK5uWBkgSXJaRLr4+3A6g==} + + canonicalize@2.1.0: + resolution: {integrity: sha512-F705O3xrsUtgt98j7leetNhTWPe+5S72rlL5O4jA1pKqBVQ/dT1O1D6PFxmSXvc0SUOinWS57DKx0I3CHrXJHQ==} + hasBin: true + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + chalk@5.6.2: + resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + charenc@0.0.2: + resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==} + + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + + cliui@6.0.0: + resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} + + clsx@1.2.1: + resolution: {integrity: sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==} + engines: {node: '>=6'} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + commander@14.0.0: + resolution: {integrity: sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA==} + engines: {node: '>=20'} + + commander@14.0.2: + resolution: {integrity: sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==} + engines: {node: '>=20'} + + commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + cookie-es@1.2.2: + resolution: {integrity: sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==} + + core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + + crc-32@1.2.2: + resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} + engines: {node: '>=0.8'} + hasBin: true + + cross-fetch@3.2.0: + resolution: {integrity: sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==} + + cross-fetch@4.1.0: + resolution: {integrity: sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw==} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + crossws@0.3.5: + resolution: {integrity: sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==} + + crypt@0.0.2: + resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==} + + css-color-keywords@1.0.0: + resolution: {integrity: sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==} + engines: {node: '>=4'} + + css-to-react-native@3.2.0: + resolution: {integrity: sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==} + + csstype@3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + daisyui@5.5.14: + resolution: {integrity: sha512-L47rvw7I7hK68TA97VB8Ee0woHew+/ohR6Lx6Ah/krfISOqcG4My7poNpX5Mo5/ytMxiR40fEaz6njzDi7cuSg==} + + date-fns@2.30.0: + resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==} + engines: {node: '>=0.11'} + + dateformat@4.6.3: + resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==} + + dayjs@1.11.13: + resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} + + debug@4.3.4: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decamelize@1.2.0: + resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} + engines: {node: '>=0.10.0'} + + decode-uri-component@0.2.2: + resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==} + engines: {node: '>=0.10'} + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + defu@6.1.4: + resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + + delay@5.0.0: + resolution: {integrity: sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==} + engines: {node: '>=10'} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + derive-valtio@0.1.0: + resolution: {integrity: sha512-OCg2UsLbXK7GmmpzMXhYkdO64vhJ1ROUUGaTFyHjVwEdMEcTTRj7W1TxLbSBxdY8QLBPCcp66MTyaSy0RpO17A==} + peerDependencies: + valtio: '*' + + destr@2.0.5: + resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} + + detect-browser@5.3.0: + resolution: {integrity: sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w==} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + dijkstrajs@1.0.3: + resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + duplexify@4.1.3: + resolution: {integrity: sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==} + + eciesjs@0.4.16: + resolution: {integrity: sha512-dS5cbA9rA2VR4Ybuvhg6jvdmp46ubLn3E+px8cG/35aEDNclrqoCjg6mt0HYZ/M+OoESS3jSkCrqk1kWAEhWAw==} + engines: {bun: '>=1', deno: '>=2', node: '>=16'} + + electron-to-chromium@1.5.267: + resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + encode-utf8@1.0.3: + resolution: {integrity: sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==} + + end-of-stream@1.4.5: + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} + + engine.io-client@6.6.4: + resolution: {integrity: sha512-+kjUJnZGwzewFDw951CDWcwj35vMNf2fcj7xQWOctq1F2i1jkDdVvdFG9kM/BEChymCH36KgjnW0NsL58JYRxw==} + + engine.io-parser@5.2.3: + resolution: {integrity: sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==} + engines: {node: '>=10.0.0'} + + enhanced-resolve@5.18.4: + resolution: {integrity: sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==} + engines: {node: '>=10.13.0'} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + es-toolkit@1.33.0: + resolution: {integrity: sha512-X13Q/ZSc+vsO1q600bvNK4bxgXMkHcf//RxCmYDaRY5DAcT+eoXjY5hoAPGMdRnWQjvyLEcyauG3b6hz76LNqg==} + + es-toolkit@1.39.3: + resolution: {integrity: sha512-Qb/TCFCldgOy8lZ5uC7nLGdqJwSabkQiYQShmw4jyiPk1pZzaYWTwaYKYP7EgLccWYgZocMrtItrwh683voaww==} + + es6-promise@4.2.8: + resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==} + + es6-promisify@5.0.0: + resolution: {integrity: sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==} + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + eslint-plugin-react-hooks@7.0.1: + resolution: {integrity: sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==} + engines: {node: '>=18'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 + + eslint-plugin-react-refresh@0.4.26: + resolution: {integrity: sha512-1RETEylht2O6FM/MvgnyvT+8K21wLqDNg4qD51Zj3guhjt433XbnnkVttHMyaVyAFD03QSV4LPS5iE3VQmO7XQ==} + peerDependencies: + eslint: '>=8.40' + + eslint-scope@8.4.0: + resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.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-visitor-keys@4.2.1: + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint@9.39.2: + resolution: {integrity: sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + espree@10.4.0: + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + esquery@1.6.0: + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + 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'} + + eth-block-tracker@7.1.0: + resolution: {integrity: sha512-8YdplnuE1IK4xfqpf4iU7oBxnOYAc35934o083G8ao+8WM8QQtt/mVlAY6yIAdY1eMeLqg4Z//PZjJGmWGPMRg==} + engines: {node: '>=14.0.0'} + + eth-json-rpc-filters@6.0.1: + resolution: {integrity: sha512-ITJTvqoCw6OVMLs7pI8f4gG92n/St6x80ACtHodeS+IXmO0w+t1T5OOzfSt7KLSMLRkVUoexV7tztLgDxg+iig==} + engines: {node: '>=14.0.0'} + + eth-query@2.1.2: + resolution: {integrity: sha512-srES0ZcvwkR/wd5OQBRA1bIJMww1skfGS0s8wlwK3/oNP4+wnds60krvu5R1QbpRQjMmpG5OMIWro5s7gvDPsA==} + + eth-rpc-errors@4.0.3: + resolution: {integrity: sha512-Z3ymjopaoft7JDoxZcEb3pwdGh7yiYMhOwm2doUt6ASXlMavpNlK6Cre0+IMl2VSGyEU9rkiperQhp5iRxn5Pg==} + + ethereum-cryptography@2.2.1: + resolution: {integrity: sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==} + + event-target-shim@5.0.1: + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} + + eventemitter2@6.4.9: + resolution: {integrity: sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==} + + eventemitter3@5.0.1: + resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + + events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + + extension-port-stream@3.0.0: + resolution: {integrity: sha512-an2S5quJMiy5bnZKEf6AkfH/7r8CzHvhchU40gxN+OM6HPhe7Z9T1FUychcf2M9PpPOO0Hf7BAEfJkw2TDIBDw==} + engines: {node: '>=12.0.0'} + + eyes@0.1.8: + resolution: {integrity: sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==} + engines: {node: '> 0.1.90'} + + fast-copy@3.0.2: + resolution: {integrity: sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fast-password-entropy@1.1.1: + resolution: {integrity: sha512-dxm29/BPFrNgyEDygg/lf9c2xQR0vnQhG7+hZjAI39M/3um9fD4xiqG6F0ZjW6bya5m9CI0u6YryHGRtxCGCiw==} + + fast-redact@3.5.0: + resolution: {integrity: sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==} + engines: {node: '>=6'} + + fast-safe-stringify@2.1.1: + resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} + + fast-stable-stringify@1.0.0: + resolution: {integrity: sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag==} + + fastestsmallesttextencoderdecoder@1.0.22: + resolution: {integrity: sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + fetch-retry@6.0.0: + resolution: {integrity: sha512-BUFj1aMubgib37I3v4q78fYo63Po7t4HUPTpQ6/QE6yK6cIQrP+W43FYToeTEyg5m2Y7eFUtijUuAv/PDlWuag==} + + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + + filter-obj@1.1.0: + resolution: {integrity: sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==} + engines: {node: '>=0.10.0'} + + 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@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + + flatted@3.3.3: + resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + + follow-redirects@1.15.11: + resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + for-each@0.3.5: + resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} + engines: {node: '>= 0.4'} + + form-data@4.0.5: + resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} + engines: {node: '>= 6'} + + 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==} + + generator-function@2.0.1: + resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} + engines: {node: '>= 0.4'} + + 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-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + + globals@16.5.0: + resolution: {integrity: sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==} + engines: {node: '>=18'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + h3@1.15.4: + resolution: {integrity: sha512-z5cFQWDffyOe4vQ9xIqNfCZdV4p//vy6fBnr8Q1AWnVZ0teurKMG66rLj++TKwKPUP3u7iMUvrvKaEUiQw2QWQ==} + + 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-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + 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'} + + help-me@5.0.0: + resolution: {integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==} + + hermes-estree@0.25.1: + resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} + + hermes-parser@0.25.1: + resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} + + hono@4.11.1: + resolution: {integrity: sha512-KsFcH0xxHes0J4zaQgWbYwmz3UPOOskdqZmItstUG93+Wk1ePBLkLGwbP9zlmh1BFUiL8Qp+Xfu9P7feJWpGNg==} + engines: {node: '>=16.9.0'} + + humanize-ms@1.2.1: + resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} + + idb-keyval@6.2.1: + resolution: {integrity: sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg==} + + idb-keyval@6.2.2: + resolution: {integrity: sha512-yjD9nARJ/jb1g+CvD0tlhUHOrJ9Sy0P8T9MF3YaLlHnSRpwPfpTX0XIvpmw3gAJUmEu3FiICLBDPXVwyEvrleg==} + + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + iron-webcrypto@1.2.1: + resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==} + + is-arguments@1.2.0: + resolution: {integrity: sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==} + engines: {node: '>= 0.4'} + + is-buffer@1.1.6: + resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} + + is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + 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-function@1.1.2: + resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==} + engines: {node: '>= 0.4'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-regex@1.2.1: + resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} + engines: {node: '>= 0.4'} + + is-retry-allowed@2.2.0: + resolution: {integrity: sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg==} + engines: {node: '>=10'} + + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + + is-typed-array@1.1.15: + resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} + engines: {node: '>= 0.4'} + + isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + + isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + isomorphic-ws@4.0.1: + resolution: {integrity: sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==} + peerDependencies: + ws: '*' + + isows@1.0.6: + resolution: {integrity: sha512-lPHCayd40oW98/I0uvgaHKWCSvkzY27LjWLbtzOm64yQ+G3Q5npjjbdppU65iZXkK1Zt+kH9pfegli0AYfwYYw==} + peerDependencies: + ws: '*' + + isows@1.0.7: + resolution: {integrity: sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg==} + peerDependencies: + ws: '*' + + jayson@4.3.0: + resolution: {integrity: sha512-AauzHcUcqs8OBnCHOkJY280VaTiCm57AbuO7lqzcw7JapGj50BisE3xhksye4zlTSR1+1tAz67wLTl8tEH1obQ==} + engines: {node: '>=8'} + hasBin: true + + jiti@2.6.1: + resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} + hasBin: true + + jose@4.15.9: + resolution: {integrity: sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==} + + jose@6.1.3: + resolution: {integrity: sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==} + + joycon@3.1.1: + resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} + engines: {node: '>=10'} + + js-cookie@3.0.5: + resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==} + engines: {node: '>=14'} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@4.1.1: + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} + hasBin: true + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-rpc-engine@6.1.0: + resolution: {integrity: sha512-NEdLrtrq1jUZyfjkr9OCz9EzCNhnRyWtt1PAnvnhwy6e8XETS0Dtc+ZNCO2gvuAoKsIn2+vCSowXTYE4CkgnAQ==} + engines: {node: '>=10.0.0'} + + json-rpc-random-id@1.0.1: + resolution: {integrity: sha512-RJ9YYNCkhVDBuP4zN5BBtYAzEl03yq/jIIsyif0JY9qyJuQQZNeDK7anAPKKlyEtLSj2s8h6hNh2F8zO5q7ScA==} + + 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==} + + json-stringify-safe@5.0.1: + resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + keccak@3.0.4: + resolution: {integrity: sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q==} + engines: {node: '>=10.0.0'} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + keyvaluestorage-interface@1.0.0: + resolution: {integrity: sha512-8t6Q3TclQ4uZynJY9IGr2+SsIGwK9JHcO6ootkHCGA0CrQCRy+VkouYNO2xicET6b9al7QKzpebNow+gkpCL8g==} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + libphonenumber-js@1.12.33: + resolution: {integrity: sha512-r9kw4OA6oDO4dPXkOrXTkArQAafIKAU71hChInV4FxZ69dxCfbwQGDPzqR5/vea94wU705/3AZroEbSoeVWrQw==} + + lightningcss-android-arm64@1.30.2: + resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.30.2: + resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.30.2: + resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.30.2: + resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.30.2: + resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.30.2: + resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.30.2: + resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-x64-gnu@1.30.2: + resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-musl@1.30.2: + resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-win32-arm64-msvc@1.30.2: + resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.30.2: + resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.30.2: + resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} + engines: {node: '>= 12.0.0'} + + lit-element@4.2.1: + resolution: {integrity: sha512-WGAWRGzirAgyphK2urmYOV72tlvnxw7YfyLDgQ+OZnM9vQQBQnumQ7jUJe6unEzwGU3ahFOjuz1iz1jjrpCPuw==} + + lit-html@3.3.1: + resolution: {integrity: sha512-S9hbyDu/vs1qNrithiNyeyv64c9yqiW9l+DBgI18fL+MTvOtWoFR0FWiyq1TxaYef5wNlpEmzlXoBlZEO+WjoA==} + + lit@3.3.0: + resolution: {integrity: sha512-DGVsqsOIHBww2DqnuZzW7QsuCdahp50ojuDaBPC7jUDRpYoH0z7kHBBYZewRzer75FwtrkmkKk7iOAwSaWdBmw==} + + 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.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + lucide-react@0.554.0: + resolution: {integrity: sha512-St+z29uthEJVx0Is7ellNkgTEhaeSoA42I7JjOCBCrc5X6LYMGSv0P/2uS5HDLTExP5tpiqRD2PyUEOS6s9UXA==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + md5@2.3.0: + resolution: {integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==} + + micro-ftch@0.3.1: + resolution: {integrity: sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg==} + + 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'} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + mipd@0.0.7: + resolution: {integrity: sha512-aAPZPNDQ3uMTdKbuO2YmAw2TxLHO0moa4YKAyETM/DTj5FloZo+a+8tU+iv4GmW+sOxKLSRwcSFuczk+Cpt6fg==} + peerDependencies: + typescript: '>=5.0.4' + peerDependenciesMeta: + typescript: + optional: 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==} + + multiformats@9.9.0: + resolution: {integrity: sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + node-addon-api@2.0.2: + resolution: {integrity: sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==} + + node-fetch-native@1.6.7: + resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} + + node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + + node-gyp-build@4.8.4: + resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} + hasBin: true + + node-mock-http@1.0.4: + resolution: {integrity: sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ==} + + node-releases@2.0.27: + resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + obj-multiplex@1.0.0: + resolution: {integrity: sha512-0GNJAOsHoBHeNTvl5Vt6IWnpUEcc3uSRxzBri7EDyIcMgYvnY2JL2qdeV5zTMjWQX5OHcD5amcW2HFfDh0gjIA==} + + ofetch@1.5.1: + resolution: {integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==} + + on-exit-leak-free@0.2.0: + resolution: {integrity: sha512-dqaz3u44QbRXQooZLTUKU41ZrzYrcvLISVgbrzbyCMxpmSLJvZ3ZamIJIZ29P6OhZIkNIQKosdeM6t1LYbA9hg==} + + on-exit-leak-free@2.1.2: + resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} + engines: {node: '>=14.0.0'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + openapi-fetch@0.13.8: + resolution: {integrity: sha512-yJ4QKRyNxE44baQ9mY5+r/kAzZ8yXMemtNAOFwOzRXJscdjSxxzWSNlyBAr+o5JjkUw9Lc3W7OIoca0cY3PYnQ==} + + openapi-typescript-helpers@0.0.15: + resolution: {integrity: sha512-opyTPaunsklCBpTK8JGef6mfPhLSnyy5a0IN9vKtx3+4aExf+KxEqYwIy3hqkedXIB97u357uLMJsOnm3GVjsw==} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + ox@0.11.1: + resolution: {integrity: sha512-1l1gOLAqg0S0xiN1dH5nkPna8PucrZgrIJOfS49MLNiMevxu07Iz4ZjuJS9N+xifvT+PsZyIptS7WHM8nC+0+A==} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + ox@0.6.7: + resolution: {integrity: sha512-17Gk/eFsFRAZ80p5eKqv89a57uXjd3NgIf1CaXojATPBuujVc/fQSVhBeAU9JCRB+k7J50WQAyWTxK19T9GgbA==} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + ox@0.6.9: + resolution: {integrity: sha512-wi5ShvzE4eOcTwQVsIPdFr+8ycyX+5le/96iAJutaZAvCes1J0+RvpEPg5QDPDiaR0XQQAvZVl7AwqQcINuUug==} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + ox@0.9.1: + resolution: {integrity: sha512-NVI0cajROntJWtFnxZQ1aXDVy+c6DLEXJ3wwON48CgbPhmMJrpRTfVbuppR+47RmXm3lZ/uMaKiFSkLdAO1now==} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + ox@0.9.17: + resolution: {integrity: sha512-rKAnhzhRU3Xh3hiko+i1ZxywZ55eWQzeS/Q4HRKLx2PqfHOolisZHErSsJVipGlmQKHW5qwOED/GighEw9dbLg==} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + ox@0.9.3: + resolution: {integrity: sha512-KzyJP+fPV4uhuuqrTZyok4DC7vFzi7HLUFiUNEmpbyh59htKWkOC98IONC1zgXJPbHAhQgqs6B0Z6StCGhmQvg==} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + 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'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + + pify@3.0.0: + resolution: {integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==} + engines: {node: '>=4'} + + pify@5.0.0: + resolution: {integrity: sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==} + engines: {node: '>=10'} + + pino-abstract-transport@0.5.0: + resolution: {integrity: sha512-+KAgmVeqXYbTtU2FScx1XS3kNyfZ5TrXY07V96QnUSFqo2gAqlvmaxH67Lj7SWazqsMabf+58ctdTcBgnOLUOQ==} + + pino-abstract-transport@1.2.0: + resolution: {integrity: sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q==} + + pino-abstract-transport@2.0.0: + resolution: {integrity: sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==} + + pino-pretty@10.3.1: + resolution: {integrity: sha512-az8JbIYeN/1iLj2t0jR9DV48/LQ3RC6hZPpapKPkb84Q+yTidMCpgWxIT3N0flnBDilyBQ1luWNpOeJptjdp/g==} + hasBin: true + + pino-std-serializers@4.0.0: + resolution: {integrity: sha512-cK0pekc1Kjy5w9V2/n+8MkZwusa6EyyxfeQCB799CQRhRt/CqYKiWs5adeu8Shve2ZNffvfC/7J64A2PJo1W/Q==} + + pino-std-serializers@7.0.0: + resolution: {integrity: sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==} + + pino@10.0.0: + resolution: {integrity: sha512-eI9pKwWEix40kfvSzqEP6ldqOoBIN7dwD/o91TY5z8vQI12sAffpR/pOqAD1IVVwIVHDpHjkq0joBPdJD0rafA==} + hasBin: true + + pino@7.11.0: + resolution: {integrity: sha512-dMACeu63HtRLmCG8VKdy4cShCPKaYDR4youZqoSWLxl5Gu99HUw8bw75thbPv9Nip+H+QYX8o3ZJbTdVZZ2TVg==} + hasBin: true + + pngjs@5.0.0: + resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==} + engines: {node: '>=10.13.0'} + + pony-cause@2.1.11: + resolution: {integrity: sha512-M7LhCsdNbNgiLYiP4WjsfLUuFmCfnjdF6jKe2R9NKl4WFN+HZPGHJZ9lnLP7f9ZnKe3U9nuWD0szirmj+migUg==} + engines: {node: '>=12.0.0'} + + porto@0.2.35: + resolution: {integrity: sha512-gu9FfjjvvYBgQXUHWTp6n3wkTxVtEcqFotM7i3GEZeoQbvLGbssAicCz6hFZ8+xggrJWwi/RLmbwNra50SMmUQ==} + hasBin: true + peerDependencies: + '@tanstack/react-query': '>=5.59.0' + '@wagmi/core': '>=2.16.3' + expo-auth-session: '>=7.0.8' + expo-crypto: '>=15.0.7' + expo-web-browser: '>=15.0.8' + react: '>=18' + react-native: '>=0.81.4' + typescript: '>=5.4.0' + viem: '>=2.37.0' + wagmi: '>=2.0.0' + peerDependenciesMeta: + '@tanstack/react-query': + optional: true + expo-auth-session: + optional: true + expo-crypto: + optional: true + expo-web-browser: + optional: true + react: + optional: true + react-native: + optional: true + typescript: + optional: true + wagmi: + optional: true + + possible-typed-array-names@1.1.0: + resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} + engines: {node: '>= 0.4'} + + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + + postcss@8.4.49: + resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} + engines: {node: ^10 || ^12 || >=14} + + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} + + preact@10.24.2: + resolution: {integrity: sha512-1cSoF0aCC8uaARATfrlz4VCBqE8LwZwRfLgkxJOQwAlQt6ayTmi0D9OF7nXid1POI5SZidFuG9CnlXbDfLqY/Q==} + + preact@10.28.0: + resolution: {integrity: sha512-rytDAoiXr3+t6OIP3WGlDd0ouCUG1iCWzkcY3++Nreuoi17y6T5i/zRhe6uYfoVcxq6YU+sBtJouuRDsq8vvqA==} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + + process-warning@1.0.0: + resolution: {integrity: sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q==} + + process-warning@5.0.0: + resolution: {integrity: sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==} + + process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + + proxy-compare@2.6.0: + resolution: {integrity: sha512-8xuCeM3l8yqdmbPoYeLbrAXCBWu19XEYc5/F28f5qOaoAIMyfmBUkl5axiK+x9olUvRlcekvnm98AP9RDngOIw==} + + proxy-compare@3.0.1: + resolution: {integrity: sha512-V9plBAt3qjMlS1+nC8771KNf6oJ12gExvaxnNzN/9yVRLdTv/lc+oJlnSzrdYDAvBfTStPCoiaCOTmTs0adv7Q==} + + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + + pump@3.0.3: + resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + qrcode@1.5.3: + resolution: {integrity: sha512-puyri6ApkEHYiVl4CFzo1tDkAZ+ATcnbJrJ6RiBM1Fhctdn/ix9MTE3hRph33omisEbC/2fcfemsseiKgBPKZg==} + engines: {node: '>=10.13.0'} + hasBin: true + + qrcode@1.5.4: + resolution: {integrity: sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==} + engines: {node: '>=10.13.0'} + hasBin: true + + query-string@7.1.3: + resolution: {integrity: sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==} + engines: {node: '>=6'} + + quick-format-unescaped@4.0.4: + resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} + + radix3@1.1.2: + resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} + + react-device-detect@2.2.3: + resolution: {integrity: sha512-buYY3qrCnQVlIFHrC5UcUoAj7iANs/+srdkwsnNjI7anr3Tt7UY6MqNxtMLlr0tMBied0O49UZVK8XKs3ZIiPw==} + peerDependencies: + react: '>= 0.14.0' + react-dom: '>= 0.14.0' + + react-dom@19.2.3: + resolution: {integrity: sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==} + peerDependencies: + react: ^19.2.3 + + react-refresh@0.18.0: + resolution: {integrity: sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==} + engines: {node: '>=0.10.0'} + + react@19.2.3: + resolution: {integrity: sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==} + engines: {node: '>=0.10.0'} + + readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + + readable-stream@4.7.0: + resolution: {integrity: sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + + real-require@0.1.0: + resolution: {integrity: sha512-r/H9MzAWtrv8aSVjPCMFpDMl5q66GqtmmRkRjpHTsp4zBAa+snZyiQNlMONiUmEJcsnaw0wCauJ2GWODr/aFkg==} + engines: {node: '>= 12.13.0'} + + real-require@0.2.0: + resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} + engines: {node: '>= 12.13.0'} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + require-main-filename@2.0.0: + resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + rolldown-vite@7.3.0: + resolution: {integrity: sha512-5hI5NCJwKBGtzWtdKB3c2fOEpI77Iaa0z4mSzZPU1cJ/OqrGbFafm90edVCd7T9Snz+Sh09TMAv4EQqyVLzuEg==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + esbuild: ^0.27.0 + jiti: '>=1.21.0' + less: ^4.0.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + rolldown@1.0.0-beta.53: + resolution: {integrity: sha512-Qd9c2p0XKZdgT5AYd+KgAMggJ8ZmCs3JnS9PTMWkyUfteKlfmKtxJbWTHkVakxwXs1Ub7jrRYVeFeF7N0sQxyw==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + + rpc-websockets@9.3.2: + resolution: {integrity: sha512-VuW2xJDnl1k8n8kjbdRSWawPRkwaVqUQNjE1TdeTawf0y0abGhtVJFTXCLfgpgGDBkO/Fj6kny8Dc/nvOW78MA==} + + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safe-regex-test@1.1.0: + resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} + engines: {node: '>= 0.4'} + + safe-stable-stringify@2.5.0: + resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} + engines: {node: '>=10'} + + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + + secure-json-parse@2.7.0: + resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} + + secure-password-utilities@0.2.1: + resolution: {integrity: sha512-znUg8ae3cpuAaogiFBhP82gD2daVkSz4Qv/L7OWjB7wWvfbCdeqqQuJkm2/IvhKQPOV0T739YPR6rb7vs0uWaw==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.7.2: + resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} + engines: {node: '>=10'} + hasBin: true + + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + engines: {node: '>=10'} + hasBin: true + + set-blocking@2.0.0: + resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + + set-cookie-parser@2.7.2: + resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} + + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + sha.js@2.4.12: + resolution: {integrity: sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==} + engines: {node: '>= 0.10'} + hasBin: true + + shallowequal@1.1.0: + resolution: {integrity: sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==} + + 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'} + + slow-redact@0.3.2: + resolution: {integrity: sha512-MseHyi2+E/hBRqdOi5COy6wZ7j7DxXRz9NkseavNYSvvWC06D8a5cidVZX3tcG5eCW3NIyVU4zT63hw0Q486jw==} + + socket.io-client@4.8.2: + resolution: {integrity: sha512-4MY14EMsyEPFA6lM01XIYepRdV8P6dUir2hxAlAysOYcbNAy5QNHYgIHOcQ1KYM7wTcKnKEW/ZRoIxRinWRXvA==} + engines: {node: '>=10.0.0'} + + socket.io-parser@4.2.5: + resolution: {integrity: sha512-bPMmpy/5WWKHea5Y/jYAP6k74A+hvmRCQaJuJB6I/ML5JZq/KfNieUVo/3Mh7SAqn7TyFdIo6wqYHInG1MU1bQ==} + engines: {node: '>=10.0.0'} + + sonic-boom@2.8.0: + resolution: {integrity: sha512-kuonw1YOYYNOve5iHdSahXPOK49GqwA+LZhI6Wz/l0rP57iKyXXIHaRagOBHAPmGwJC6od2Z9zgvZ5loSgMlVg==} + + sonic-boom@3.8.1: + resolution: {integrity: sha512-y4Z8LCDBuum+PBP3lSV7RHrXscqksve/bi0as7mhwVnBW+/wUqKT/2Kb7um8yqcFy0duYbbPxzt89Zy2nOCaxg==} + + sonic-boom@4.2.0: + resolution: {integrity: sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + split-on-first@1.1.0: + resolution: {integrity: sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==} + engines: {node: '>=6'} + + split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + + stream-chain@2.2.5: + resolution: {integrity: sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA==} + + stream-json@1.9.1: + resolution: {integrity: sha512-uWkjJ+2Nt/LO9Z/JyKZbMusL8Dkh97uUBTv3AJQ74y07lVahLY4eEFsPsE97pxYBwr8nnjMAIch5eqI0gPShyw==} + + stream-shift@1.0.3: + resolution: {integrity: sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==} + + strict-uri-encode@2.0.0: + resolution: {integrity: sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==} + engines: {node: '>=4'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + styled-components@6.1.19: + resolution: {integrity: sha512-1v/e3Dl1BknC37cXMhwGomhO8AkYmN41CqyX9xhUDxry1ns3BFQy2lLDRQXJRdVVWB9OHemv/53xaStimvWyuA==} + engines: {node: '>= 16'} + peerDependencies: + react: '>= 16.8.0' + react-dom: '>= 16.8.0' + + stylis@4.3.2: + resolution: {integrity: sha512-bhtUjWd/z6ltJiQwg0dUfxEJ+W+jdqQd8TbWLWyeIJHlnsqmGLRFFd8e5mA0AZi/zx90smXRlN66YMTcaSFifg==} + + stylis@4.3.6: + resolution: {integrity: sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==} + + superstruct@1.0.4: + resolution: {integrity: sha512-7JpaAoX2NGyoFlI9NBh66BQXGONc+uE+MRS5i2iOBKuS4e+ccgMDjATgZldkah+33DakBxDHiss9kvUcGAO8UQ==} + engines: {node: '>=14.0.0'} + + superstruct@2.0.2: + resolution: {integrity: sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A==} + engines: {node: '>=14.0.0'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + tabbable@6.3.0: + resolution: {integrity: sha512-EIHvdY5bPLuWForiR/AN2Bxngzpuwn1is4asboytXtpTgsArc+WmSJKVLlhdh71u7jFcryDqB2A8lQvj78MkyQ==} + + tailwindcss@4.1.18: + resolution: {integrity: sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==} + + tapable@2.3.0: + resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} + engines: {node: '>=6'} + + text-encoding-utf-8@1.0.2: + resolution: {integrity: sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==} + + thread-stream@0.15.2: + resolution: {integrity: sha512-UkEhKIg2pD+fjkHQKyJO3yoIvAP3N6RlNFt2dUhcS1FGvCD1cQa1M/PGknCLFIyZdtJOWQjejp7bdNqmN7zwdA==} + + thread-stream@3.1.0: + resolution: {integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==} + + tinycolor2@1.6.0: + resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==} + + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} + + to-buffer@1.2.2: + resolution: {integrity: sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==} + engines: {node: '>= 0.4'} + + tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + + ts-api-utils@2.1.0: + resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + + tslib@1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + + tslib@2.6.2: + resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + typed-array-buffer@1.0.3: + resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} + engines: {node: '>= 0.4'} + + typescript-eslint@8.50.1: + resolution: {integrity: sha512-ytTHO+SoYSbhAH9CrYnMhiLx8To6PSSvqnvXyPUgPETCvB6eBKmTI9w6XMPS3HsBRGkwTVBX+urA8dYQx6bHfQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + ua-parser-js@1.0.41: + resolution: {integrity: sha512-LbBDqdIC5s8iROCUjMbW1f5dJQTEFB1+KO9ogbvlb3nm9n4YHa5p4KTvFPWvh2Hs8gZMBuiB1/8+pdfe/tDPug==} + hasBin: true + + ufo@1.6.1: + resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} + + uint8arrays@3.1.0: + resolution: {integrity: sha512-ei5rfKtoRO8OyOIor2Rz5fhzjThwIHJZ3uyDPnDHTXbP0aMQ1RN/6AI5B5d9dBxJOU+BvOAk7ZQ1xphsX8Lrog==} + + uint8arrays@3.1.1: + resolution: {integrity: sha512-+QJa8QRnbdXVpHYjLoTpJIdCTiw9Ir62nocClWuXIq2JIh4Uta0cQsTSpFL678p2CN8B+XSApwcU+pQEqVpKWg==} + + uncrypto@0.1.3: + resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} + + undici-types@7.16.0: + resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + + unstorage@1.17.3: + resolution: {integrity: sha512-i+JYyy0DoKmQ3FximTHbGadmIYb8JEpq7lxUjnjeB702bCPum0vzo6oy5Mfu0lpqISw7hCyMW2yj4nWC8bqJ3Q==} + peerDependencies: + '@azure/app-configuration': ^1.8.0 + '@azure/cosmos': ^4.2.0 + '@azure/data-tables': ^13.3.0 + '@azure/identity': ^4.6.0 + '@azure/keyvault-secrets': ^4.9.0 + '@azure/storage-blob': ^12.26.0 + '@capacitor/preferences': ^6.0.3 || ^7.0.0 + '@deno/kv': '>=0.9.0' + '@netlify/blobs': ^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0 + '@planetscale/database': ^1.19.0 + '@upstash/redis': ^1.34.3 + '@vercel/blob': '>=0.27.1' + '@vercel/functions': ^2.2.12 || ^3.0.0 + '@vercel/kv': ^1.0.1 + aws4fetch: ^1.0.20 + db0: '>=0.2.1' + idb-keyval: ^6.2.1 + ioredis: ^5.4.2 + uploadthing: ^7.4.4 + peerDependenciesMeta: + '@azure/app-configuration': + optional: true + '@azure/cosmos': + optional: true + '@azure/data-tables': + optional: true + '@azure/identity': + optional: true + '@azure/keyvault-secrets': + optional: true + '@azure/storage-blob': + optional: true + '@capacitor/preferences': + optional: true + '@deno/kv': + optional: true + '@netlify/blobs': + optional: true + '@planetscale/database': + optional: true + '@upstash/redis': + optional: true + '@vercel/blob': + optional: true + '@vercel/functions': + optional: true + '@vercel/kv': + optional: true + aws4fetch: + optional: true + db0: + optional: true + idb-keyval: + optional: true + ioredis: + optional: true + uploadthing: + optional: true + + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + use-sync-external-store@1.2.0: + resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + + use-sync-external-store@1.4.0: + resolution: {integrity: sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + use-sync-external-store@1.6.0: + resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + utf-8-validate@5.0.10: + resolution: {integrity: sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==} + engines: {node: '>=6.14.2'} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + util@0.12.5: + resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==} + + uuid@8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + hasBin: true + + uuid@9.0.1: + resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} + hasBin: true + + valtio@1.13.2: + resolution: {integrity: sha512-Qik0o+DSy741TmkqmRfjq+0xpZBXi/Y6+fXZLn0xNF1z/waFMbE3rkivv5Zcf9RrMUp6zswf2J7sbh2KBlba5A==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=16.8' + react: '>=16.8' + peerDependenciesMeta: + '@types/react': + optional: true + react: + optional: true + + valtio@2.1.7: + resolution: {integrity: sha512-DwJhCDpujuQuKdJ2H84VbTjEJJteaSmqsuUltsfbfdbotVfNeTE4K/qc/Wi57I9x8/2ed4JNdjEna7O6PfavRg==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=18.0.0' + react: '>=18.0.0' + peerDependenciesMeta: + '@types/react': + optional: true + react: + optional: true + + viem@2.23.2: + resolution: {integrity: sha512-NVmW/E0c5crMOtbEAqMF0e3NmvQykFXhLOc/CkLIXOlzHSA6KXVz3CYVmaKqBF8/xtjsjHAGjdJN3Ru1kFJLaA==} + peerDependencies: + typescript: '>=5.0.4' + peerDependenciesMeta: + typescript: + optional: true + + viem@2.36.0: + resolution: {integrity: sha512-Xz7AkGtR43K+NY74X2lBevwfRrsXuifGUzt8QiULO47NXIcT7g3jcA4nIvl5m2OTE5v8SlzishwXmg64xOIVmQ==} + peerDependencies: + typescript: '>=5.0.4' + peerDependenciesMeta: + typescript: + optional: true + + viem@2.43.3: + resolution: {integrity: sha512-zM251fspfSjENCtfmT7cauuD+AA/YAlkFU7cksdEQJxj7wDuO0XFRWRH+RMvfmTFza88B9kug5cKU+Wk2nAjJg==} + peerDependencies: + typescript: '>=5.0.4' + peerDependenciesMeta: + typescript: + optional: true + + wagmi@2.19.5: + resolution: {integrity: sha512-RQUfKMv6U+EcSNNGiPbdkDtJwtuFxZWLmvDiQmjjBgkuPulUwDJsKhi7gjynzJdsx2yDqhHCXkKsbbfbIsHfcQ==} + peerDependencies: + '@tanstack/react-query': '>=5.0.0' + react: '>=18' + typescript: '>=5.0.4' + viem: 2.x + peerDependenciesMeta: + typescript: + optional: true + + wagmi@3.1.1: + resolution: {integrity: sha512-ahfYf70IEDTNl+NtetBBaKO2cgCA3SRiMMskN/bUjOC4Kr91HoUHVOw1OonLTbT+41D5m+5PxwtHeTRosaH5Uw==} + peerDependencies: + '@tanstack/react-query': '>=5.0.0' + react: '>=18' + typescript: '>=5.7.3' + viem: 2.x + peerDependenciesMeta: + typescript: + optional: true + + webextension-polyfill@0.10.0: + resolution: {integrity: sha512-c5s35LgVa5tFaHhrZDnr3FpQpjj1BB+RXhLTYUxGqBVN460HkbM8TBtEqdXWbpTKfzwCcjAZVF7zXCYSKtcp9g==} + + webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + + whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + + which-module@2.0.1: + resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} + + which-typed-array@1.1.19: + resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==} + 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'} + + wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + ws@7.5.10: + resolution: {integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==} + engines: {node: '>=8.3.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + ws@8.18.0: + resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + ws@8.18.3: + resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + x402@0.7.3: + resolution: {integrity: sha512-8CIZsdMTOn52PjMH/ErVke9ebeZ7ErwiZ5FL3tN3Wny7Ynxs3LkuB/0q7IoccRLdVXA7f2lueYBJ2iDrElhXnA==} + + xmlhttprequest-ssl@2.1.2: + resolution: {integrity: sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==} + engines: {node: '>=0.4.0'} + + xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + + y18n@4.0.3: + resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yargs-parser@18.1.3: + resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} + engines: {node: '>=6'} + + yargs@15.4.1: + resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} + engines: {node: '>=8'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + zod-validation-error@4.0.2: + resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + zod: ^3.25.0 || ^4.0.0 + + zod@3.22.4: + resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==} + + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + + zod@4.2.1: + resolution: {integrity: sha512-0wZ1IRqGGhMP76gLqz8EyfBXKk0J2qo2+H3fi4mcUP/KtTocoX08nmIAHl1Z2kJIZbZee8KOpBCSNPRgauucjw==} + + zustand@5.0.0: + resolution: {integrity: sha512-LE+VcmbartOPM+auOjCCLQOsQ05zUTp8RkgwRzefUk+2jISdMMFnxvyTjA4YNWr5ZGXYbVsEMZosttuxUBkojQ==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=18.0.0' + immer: '>=9.0.6' + react: '>=18.0.0' + use-sync-external-store: '>=1.2.0' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + use-sync-external-store: + optional: true + + zustand@5.0.3: + resolution: {integrity: sha512-14fwWQtU3pH4dE0dOpdMiWjddcH+QzKIgk1cl8epwSE7yag43k/AD/m4L6+K7DytAOr9gGBe3/EXj9g7cdostg==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=18.0.0' + immer: '>=9.0.6' + react: '>=18.0.0' + use-sync-external-store: '>=1.2.0' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + use-sync-external-store: + optional: true + + zustand@5.0.9: + resolution: {integrity: sha512-ALBtUj0AfjJt3uNRQoL1tL2tMvj6Gp/6e39dnfT6uzpelGru8v1tPOGBzayOWbPJvujM8JojDk3E1LxeFisBNg==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=18.0.0' + immer: '>=9.0.6' + react: '>=18.0.0' + use-sync-external-store: '>=1.2.0' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + use-sync-external-store: + optional: true + +snapshots: + + '@adraffy/ens-normalize@1.11.1': {} + + '@babel/code-frame@7.27.1': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.28.5': {} + + '@babel/core@7.28.5': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.5 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) + '@babel/helpers': 7.28.4 + '@babel/parser': 7.28.5 + '@babel/template': 7.27.2 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.28.5': + dependencies: + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-compilation-targets@7.27.2': + dependencies: + '@babel/compat-data': 7.28.5 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.28.1 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-globals@7.28.0': {} + + '@babel/helper-module-imports@7.27.1': + dependencies: + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.28.5 + transitivePeerDependencies: + - supports-color + + '@babel/helper-plugin-utils@7.27.1': {} + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.28.5': {} + + '@babel/helper-validator-option@7.27.1': {} + + '@babel/helpers@7.28.4': + dependencies: + '@babel/template': 7.27.2 + '@babel/types': 7.28.5 + + '@babel/parser@7.28.5': + dependencies: + '@babel/types': 7.28.5 + + '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/runtime@7.28.4': {} + + '@babel/template@7.27.2': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + + '@babel/traverse@7.28.5': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.5 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.28.5 + '@babel/template': 7.27.2 + '@babel/types': 7.28.5 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.28.5': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + + '@base-org/account@1.1.1(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(zod@4.2.1)': + dependencies: + '@noble/hashes': 1.4.0 + clsx: 1.2.1 + eventemitter3: 5.0.1 + idb-keyval: 6.2.1 + ox: 0.6.9(typescript@5.9.3)(zod@4.2.1) + preact: 10.24.2 + viem: 2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + zustand: 5.0.3(@types/react@19.2.7)(react@19.2.3)(use-sync-external-store@1.4.0(react@19.2.3)) + transitivePeerDependencies: + - '@types/react' + - bufferutil + - immer + - react + - typescript + - use-sync-external-store + - utf-8-validate + - zod + + '@base-org/account@2.4.0(@types/react@19.2.7)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)': + dependencies: + '@coinbase/cdp-sdk': 1.40.1(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + '@noble/hashes': 1.4.0 + clsx: 1.2.1 + eventemitter3: 5.0.1 + idb-keyval: 6.2.1 + ox: 0.6.9(typescript@5.9.3)(zod@3.25.76) + preact: 10.24.2 + viem: 2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + zustand: 5.0.3(@types/react@19.2.7)(react@19.2.3)(use-sync-external-store@1.4.0(react@19.2.3)) + transitivePeerDependencies: + - '@types/react' + - bufferutil + - debug + - encoding + - fastestsmallesttextencoderdecoder + - immer + - react + - typescript + - use-sync-external-store + - utf-8-validate + - ws + - zod + + '@base-org/account@2.4.0(@types/react@19.2.7)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@4.2.1)': + dependencies: + '@coinbase/cdp-sdk': 1.40.1(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + '@noble/hashes': 1.4.0 + clsx: 1.2.1 + eventemitter3: 5.0.1 + idb-keyval: 6.2.1 + ox: 0.6.9(typescript@5.9.3)(zod@4.2.1) + preact: 10.24.2 + viem: 2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + zustand: 5.0.3(@types/react@19.2.7)(react@19.2.3)(use-sync-external-store@1.4.0(react@19.2.3)) + transitivePeerDependencies: + - '@types/react' + - bufferutil + - debug + - encoding + - fastestsmallesttextencoderdecoder + - immer + - react + - typescript + - use-sync-external-store + - utf-8-validate + - ws + - zod + optional: true + + '@coinbase/cdp-sdk@1.40.1(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10))': + dependencies: + '@solana-program/system': 0.8.1(@solana/kit@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10))) + '@solana-program/token': 0.6.0(@solana/kit@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10))) + '@solana/kit': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + '@solana/web3.js': 1.98.4(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) + abitype: 1.0.6(typescript@5.9.3)(zod@3.25.76) + axios: 1.13.2 + axios-retry: 4.5.0(axios@1.13.2) + jose: 6.1.3 + md5: 2.3.0 + uncrypto: 0.1.3 + viem: 2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + zod: 3.25.76 + transitivePeerDependencies: + - bufferutil + - debug + - encoding + - fastestsmallesttextencoderdecoder + - typescript + - utf-8-validate + - ws + + '@coinbase/wallet-sdk@3.9.3': + dependencies: + bn.js: 5.2.2 + buffer: 6.0.3 + clsx: 1.2.1 + eth-block-tracker: 7.1.0 + eth-json-rpc-filters: 6.0.1 + eventemitter3: 5.0.1 + keccak: 3.0.4 + preact: 10.28.0 + sha.js: 2.4.12 + transitivePeerDependencies: + - supports-color + + '@coinbase/wallet-sdk@4.3.2': + dependencies: + '@noble/hashes': 1.8.0 + clsx: 1.2.1 + eventemitter3: 5.0.1 + preact: 10.28.0 + + '@coinbase/wallet-sdk@4.3.6(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@noble/hashes': 1.4.0 + clsx: 1.2.1 + eventemitter3: 5.0.1 + idb-keyval: 6.2.1 + ox: 0.6.9(typescript@5.9.3)(zod@3.25.76) + preact: 10.24.2 + viem: 2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + zustand: 5.0.3(@types/react@19.2.7)(react@19.2.3)(use-sync-external-store@1.4.0(react@19.2.3)) + transitivePeerDependencies: + - '@types/react' + - bufferutil + - immer + - react + - typescript + - use-sync-external-store + - utf-8-validate + - zod + + '@coinbase/wallet-sdk@4.3.6(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(zod@4.2.1)': + dependencies: + '@noble/hashes': 1.4.0 + clsx: 1.2.1 + eventemitter3: 5.0.1 + idb-keyval: 6.2.1 + ox: 0.6.9(typescript@5.9.3)(zod@4.2.1) + preact: 10.24.2 + viem: 2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + zustand: 5.0.3(@types/react@19.2.7)(react@19.2.3)(use-sync-external-store@1.4.0(react@19.2.3)) + transitivePeerDependencies: + - '@types/react' + - bufferutil + - immer + - react + - typescript + - use-sync-external-store + - utf-8-validate + - zod + optional: true + + '@ecies/ciphers@0.2.5(@noble/ciphers@1.3.0)': + dependencies: + '@noble/ciphers': 1.3.0 + + '@emnapi/core@1.7.1': + dependencies: + '@emnapi/wasi-threads': 1.1.0 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.7.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.1.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@emotion/is-prop-valid@1.2.2': + dependencies: + '@emotion/memoize': 0.8.1 + + '@emotion/memoize@0.8.1': {} + + '@emotion/unitless@0.8.1': {} + + '@eslint-community/eslint-utils@4.9.0(eslint@9.39.2(jiti@2.6.1))': + dependencies: + eslint: 9.39.2(jiti@2.6.1) + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.2': {} + + '@eslint/config-array@0.21.1': + dependencies: + '@eslint/object-schema': 2.1.7 + debug: 4.4.3 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.4.2': + dependencies: + '@eslint/core': 0.17.0 + + '@eslint/core@0.17.0': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/eslintrc@3.3.3': + dependencies: + ajv: 6.12.6 + debug: 4.4.3 + espree: 10.4.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.1 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.39.2': {} + + '@eslint/object-schema@2.1.7': {} + + '@eslint/plugin-kit@0.4.1': + dependencies: + '@eslint/core': 0.17.0 + levn: 0.4.1 + + '@ethereumjs/common@3.2.0': + dependencies: + '@ethereumjs/util': 8.1.0 + crc-32: 1.2.2 + + '@ethereumjs/rlp@4.0.1': {} + + '@ethereumjs/tx@4.2.0': + dependencies: + '@ethereumjs/common': 3.2.0 + '@ethereumjs/rlp': 4.0.1 + '@ethereumjs/util': 8.1.0 + ethereum-cryptography: 2.2.1 + + '@ethereumjs/util@8.1.0': + dependencies: + '@ethereumjs/rlp': 4.0.1 + ethereum-cryptography: 2.2.1 + micro-ftch: 0.3.1 + + '@floating-ui/core@1.7.3': + dependencies: + '@floating-ui/utils': 0.2.10 + + '@floating-ui/dom@1.7.4': + dependencies: + '@floating-ui/core': 1.7.3 + '@floating-ui/utils': 0.2.10 + + '@floating-ui/react-dom@2.1.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@floating-ui/dom': 1.7.4 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@floating-ui/react@0.26.28(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@floating-ui/react-dom': 2.1.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@floating-ui/utils': 0.2.10 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + tabbable: 6.3.0 + + '@floating-ui/utils@0.2.10': {} + + '@gemini-wallet/core@0.3.2(viem@2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1))': + dependencies: + '@metamask/rpc-errors': 7.0.2 + eventemitter3: 5.0.1 + viem: 2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + transitivePeerDependencies: + - supports-color + + '@hcaptcha/loader@2.3.0': {} + + '@hcaptcha/react-hcaptcha@1.17.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@babel/runtime': 7.28.4 + '@hcaptcha/loader': 2.3.0 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@headlessui/react@2.2.9(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@floating-ui/react': 0.26.28(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/focus': 3.21.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/interactions': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@tanstack/react-virtual': 3.13.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + use-sync-external-store: 1.6.0(react@19.2.3) + + '@heroicons/react@2.2.0(react@19.2.3)': + dependencies: + react: 19.2.3 + + '@humanfs/core@0.19.1': {} + + '@humanfs/node@0.16.7': + dependencies: + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.4.3 + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.4.3': {} + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@lit-labs/ssr-dom-shim@1.4.0': {} + + '@lit/react@1.0.8(@types/react@19.2.7)': + dependencies: + '@types/react': 19.2.7 + optional: true + + '@lit/reactive-element@2.1.1': + dependencies: + '@lit-labs/ssr-dom-shim': 1.4.0 + + '@marsidev/react-turnstile@1.4.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@metamask/eth-json-rpc-provider@1.0.1': + dependencies: + '@metamask/json-rpc-engine': 7.3.3 + '@metamask/safe-event-emitter': 3.1.2 + '@metamask/utils': 5.0.2 + transitivePeerDependencies: + - supports-color + + '@metamask/json-rpc-engine@7.3.3': + dependencies: + '@metamask/rpc-errors': 6.4.0 + '@metamask/safe-event-emitter': 3.1.2 + '@metamask/utils': 8.5.0 + transitivePeerDependencies: + - supports-color + + '@metamask/json-rpc-engine@8.0.2': + dependencies: + '@metamask/rpc-errors': 6.4.0 + '@metamask/safe-event-emitter': 3.1.2 + '@metamask/utils': 8.5.0 + transitivePeerDependencies: + - supports-color + + '@metamask/json-rpc-middleware-stream@7.0.2': + dependencies: + '@metamask/json-rpc-engine': 8.0.2 + '@metamask/safe-event-emitter': 3.1.2 + '@metamask/utils': 8.5.0 + readable-stream: 3.6.2 + transitivePeerDependencies: + - supports-color + + '@metamask/object-multiplex@2.1.0': + dependencies: + once: 1.4.0 + readable-stream: 3.6.2 + + '@metamask/onboarding@1.0.1': + dependencies: + bowser: 2.13.1 + + '@metamask/providers@16.1.0': + dependencies: + '@metamask/json-rpc-engine': 8.0.2 + '@metamask/json-rpc-middleware-stream': 7.0.2 + '@metamask/object-multiplex': 2.1.0 + '@metamask/rpc-errors': 6.4.0 + '@metamask/safe-event-emitter': 3.1.2 + '@metamask/utils': 8.5.0 + detect-browser: 5.3.0 + extension-port-stream: 3.0.0 + fast-deep-equal: 3.1.3 + is-stream: 2.0.1 + readable-stream: 3.6.2 + webextension-polyfill: 0.10.0 + transitivePeerDependencies: + - supports-color + + '@metamask/rpc-errors@6.4.0': + dependencies: + '@metamask/utils': 9.3.0 + fast-safe-stringify: 2.1.1 + transitivePeerDependencies: + - supports-color + + '@metamask/rpc-errors@7.0.2': + dependencies: + '@metamask/utils': 11.9.0 + fast-safe-stringify: 2.1.1 + transitivePeerDependencies: + - supports-color + + '@metamask/safe-event-emitter@2.0.0': {} + + '@metamask/safe-event-emitter@3.1.2': {} + + '@metamask/sdk-analytics@0.0.5': + dependencies: + openapi-fetch: 0.13.8 + + '@metamask/sdk-communication-layer@0.33.1(cross-fetch@4.1.0)(eciesjs@0.4.16)(eventemitter2@6.4.9)(readable-stream@3.6.2)(socket.io-client@4.8.2(bufferutil@4.1.0)(utf-8-validate@5.0.10))': + dependencies: + '@metamask/sdk-analytics': 0.0.5 + bufferutil: 4.1.0 + cross-fetch: 4.1.0 + date-fns: 2.30.0 + debug: 4.3.4 + eciesjs: 0.4.16 + eventemitter2: 6.4.9 + readable-stream: 3.6.2 + socket.io-client: 4.8.2(bufferutil@4.1.0)(utf-8-validate@5.0.10) + utf-8-validate: 5.0.10 + uuid: 8.3.2 + transitivePeerDependencies: + - supports-color + + '@metamask/sdk-install-modal-web@0.32.1': + dependencies: + '@paulmillr/qr': 0.2.1 + + '@metamask/sdk@0.33.1(bufferutil@4.1.0)(utf-8-validate@5.0.10)': + dependencies: + '@babel/runtime': 7.28.4 + '@metamask/onboarding': 1.0.1 + '@metamask/providers': 16.1.0 + '@metamask/sdk-analytics': 0.0.5 + '@metamask/sdk-communication-layer': 0.33.1(cross-fetch@4.1.0)(eciesjs@0.4.16)(eventemitter2@6.4.9)(readable-stream@3.6.2)(socket.io-client@4.8.2(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + '@metamask/sdk-install-modal-web': 0.32.1 + '@paulmillr/qr': 0.2.1 + bowser: 2.13.1 + cross-fetch: 4.1.0 + debug: 4.3.4 + eciesjs: 0.4.16 + eth-rpc-errors: 4.0.3 + eventemitter2: 6.4.9 + obj-multiplex: 1.0.0 + pump: 3.0.3 + readable-stream: 3.6.2 + socket.io-client: 4.8.2(bufferutil@4.1.0)(utf-8-validate@5.0.10) + tslib: 2.8.1 + util: 0.12.5 + uuid: 8.3.2 + transitivePeerDependencies: + - bufferutil + - encoding + - supports-color + - utf-8-validate + + '@metamask/superstruct@3.2.1': {} + + '@metamask/utils@11.9.0': + dependencies: + '@ethereumjs/tx': 4.2.0 + '@metamask/superstruct': 3.2.1 + '@noble/hashes': 1.8.0 + '@scure/base': 1.2.6 + '@types/debug': 4.1.12 + '@types/lodash': 4.17.21 + debug: 4.4.3 + lodash: 4.17.21 + pony-cause: 2.1.11 + semver: 7.7.3 + uuid: 9.0.1 + transitivePeerDependencies: + - supports-color + + '@metamask/utils@5.0.2': + dependencies: + '@ethereumjs/tx': 4.2.0 + '@types/debug': 4.1.12 + debug: 4.4.3 + semver: 7.7.3 + superstruct: 1.0.4 + transitivePeerDependencies: + - supports-color + + '@metamask/utils@8.5.0': + dependencies: + '@ethereumjs/tx': 4.2.0 + '@metamask/superstruct': 3.2.1 + '@noble/hashes': 1.8.0 + '@scure/base': 1.2.6 + '@types/debug': 4.1.12 + debug: 4.4.3 + pony-cause: 2.1.11 + semver: 7.7.3 + uuid: 9.0.1 + transitivePeerDependencies: + - supports-color + + '@metamask/utils@9.3.0': + dependencies: + '@ethereumjs/tx': 4.2.0 + '@metamask/superstruct': 3.2.1 + '@noble/hashes': 1.8.0 + '@scure/base': 1.2.6 + '@types/debug': 4.1.12 + debug: 4.4.3 + pony-cause: 2.1.11 + semver: 7.7.3 + uuid: 9.0.1 + transitivePeerDependencies: + - supports-color + + '@msgpack/msgpack@3.1.2': {} + + '@napi-rs/wasm-runtime@1.1.0': + dependencies: + '@emnapi/core': 1.7.1 + '@emnapi/runtime': 1.7.1 + '@tybys/wasm-util': 0.10.1 + optional: true + + '@noble/ciphers@1.2.1': {} + + '@noble/ciphers@1.3.0': {} + + '@noble/curves@1.4.2': + dependencies: + '@noble/hashes': 1.4.0 + + '@noble/curves@1.8.0': + dependencies: + '@noble/hashes': 1.7.0 + + '@noble/curves@1.8.1': + dependencies: + '@noble/hashes': 1.7.1 + + '@noble/curves@1.9.1': + dependencies: + '@noble/hashes': 1.8.0 + + '@noble/curves@1.9.6': + dependencies: + '@noble/hashes': 1.8.0 + + '@noble/curves@1.9.7': + dependencies: + '@noble/hashes': 1.8.0 + + '@noble/hashes@1.4.0': {} + + '@noble/hashes@1.7.0': {} + + '@noble/hashes@1.7.1': {} + + '@noble/hashes@1.8.0': {} + + '@oxc-project/runtime@0.101.0': {} + + '@oxc-project/types@0.101.0': {} + + '@paulmillr/qr@0.2.1': {} + + '@phosphor-icons/webcomponents@2.1.5': + dependencies: + lit: 3.3.0 + + '@privy-io/api-base@1.7.3': + dependencies: + zod: 3.25.76 + + '@privy-io/api-types@0.3.4': {} + + '@privy-io/chains@0.0.5': {} + + '@privy-io/ethereum@0.0.4(viem@2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1))': + dependencies: + viem: 2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + + '@privy-io/js-sdk-core@0.58.4(viem@2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1))': + dependencies: + '@privy-io/api-base': 1.7.3 + '@privy-io/api-types': 0.3.4 + '@privy-io/chains': 0.0.5 + '@privy-io/ethereum': 0.0.4(viem@2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)) + '@privy-io/routes': 0.0.4 + canonicalize: 2.1.0 + eventemitter3: 5.0.1 + fetch-retry: 6.0.0 + jose: 4.15.9 + js-cookie: 3.0.5 + libphonenumber-js: 1.12.33 + set-cookie-parser: 2.7.2 + uuid: 9.0.1 + optionalDependencies: + viem: 2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + + '@privy-io/popup@0.0.1': {} + + '@privy-io/react-auth@3.9.1(@solana-program/system@0.8.1(@solana/kit@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10))))(@solana-program/token@0.9.0(@solana/kit@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10))))(@solana/kit@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10)))(@solana/sysvars@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(@tanstack/query-core@5.90.12)(@tanstack/react-query@5.90.12(react@19.2.3))(@types/react@19.2.7)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@4.2.1)': + dependencies: + '@base-org/account': 1.1.1(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(zod@4.2.1) + '@coinbase/wallet-sdk': 4.3.2 + '@floating-ui/react': 0.26.28(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@hcaptcha/react-hcaptcha': 1.17.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@headlessui/react': 2.2.9(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@heroicons/react': 2.2.0(react@19.2.3) + '@marsidev/react-turnstile': 1.4.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@privy-io/api-base': 1.7.3 + '@privy-io/api-types': 0.3.4 + '@privy-io/chains': 0.0.5 + '@privy-io/ethereum': 0.0.4(viem@2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)) + '@privy-io/js-sdk-core': 0.58.4(viem@2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)) + '@privy-io/popup': 0.0.1 + '@privy-io/routes': 0.0.4 + '@privy-io/urls': 0.0.2 + '@scure/base': 1.2.6 + '@simplewebauthn/browser': 13.2.2 + '@tanstack/react-virtual': 3.13.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@wallet-standard/app': 1.1.0 + '@walletconnect/ethereum-provider': 2.22.4(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@walletconnect/universal-provider': 2.22.4(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + eventemitter3: 5.0.1 + fast-password-entropy: 1.1.1 + jose: 4.15.9 + js-cookie: 3.0.5 + lucide-react: 0.554.0(react@19.2.3) + mipd: 0.0.7(typescript@5.9.3) + ofetch: 1.5.1 + pino-pretty: 10.3.1 + qrcode: 1.5.4 + react: 19.2.3 + react-device-detect: 2.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + react-dom: 19.2.3(react@19.2.3) + secure-password-utilities: 0.2.1 + styled-components: 6.1.19(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + stylis: 4.3.6 + tinycolor2: 1.6.0 + uuid: 9.0.1 + viem: 2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + x402: 0.7.3(@solana/sysvars@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(@tanstack/query-core@5.90.12)(@tanstack/react-query@5.90.12(react@19.2.3))(@types/react@19.2.7)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + zustand: 5.0.9(@types/react@19.2.7)(react@19.2.3)(use-sync-external-store@1.4.0(react@19.2.3)) + optionalDependencies: + '@solana-program/system': 0.8.1(@solana/kit@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10))) + '@solana-program/token': 0.9.0(@solana/kit@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10))) + '@solana/kit': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@solana/sysvars' + - '@tanstack/query-core' + - '@tanstack/react-query' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - debug + - encoding + - expo-auth-session + - expo-crypto + - expo-web-browser + - fastestsmallesttextencoderdecoder + - immer + - ioredis + - react-native + - supports-color + - typescript + - uploadthing + - use-sync-external-store + - utf-8-validate + - ws + - zod + + '@privy-io/routes@0.0.4': + dependencies: + '@privy-io/api-types': 0.3.4 + + '@privy-io/urls@0.0.2': {} + + '@privy-io/wagmi@2.1.2(f07444eeb19ffb65b1c978d9b01a05d8)': + dependencies: + '@privy-io/react-auth': 3.9.1(@solana-program/system@0.8.1(@solana/kit@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10))))(@solana-program/token@0.9.0(@solana/kit@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10))))(@solana/kit@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10)))(@solana/sysvars@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(@tanstack/query-core@5.90.12)(@tanstack/react-query@5.90.12(react@19.2.3))(@types/react@19.2.7)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@4.2.1) + react: 19.2.3 + viem: 2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + wagmi: 3.1.1(e5a60a8fcb871a16ac1f86312b108fb9) + + '@react-aria/focus@3.21.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@react-aria/interactions': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.17 + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@react-aria/interactions@3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@react-aria/ssr': 3.9.10(react@19.2.3) + '@react-aria/utils': 3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-stately/flags': 3.1.2 + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.17 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@react-aria/ssr@3.9.10(react@19.2.3)': + dependencies: + '@swc/helpers': 0.5.17 + react: 19.2.3 + + '@react-aria/utils@3.32.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@react-aria/ssr': 3.9.10(react@19.2.3) + '@react-stately/flags': 3.1.2 + '@react-stately/utils': 3.11.0(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.17 + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@react-stately/flags@3.1.2': + dependencies: + '@swc/helpers': 0.5.17 + + '@react-stately/utils@3.11.0(react@19.2.3)': + dependencies: + '@swc/helpers': 0.5.17 + react: 19.2.3 + + '@react-types/shared@3.32.1(react@19.2.3)': + dependencies: + react: 19.2.3 + + '@reown/appkit-common@1.7.8(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.22.4)': + dependencies: + big.js: 6.2.2 + dayjs: 1.11.13 + viem: 2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.22.4) + transitivePeerDependencies: + - bufferutil + - typescript + - utf-8-validate + - zod + + '@reown/appkit-common@1.7.8(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + big.js: 6.2.2 + dayjs: 1.11.13 + viem: 2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + transitivePeerDependencies: + - bufferutil + - typescript + - utf-8-validate + - zod + + '@reown/appkit-common@1.7.8(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)': + dependencies: + big.js: 6.2.2 + dayjs: 1.11.13 + viem: 2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + transitivePeerDependencies: + - bufferutil + - typescript + - utf-8-validate + - zod + optional: true + + '@reown/appkit-common@1.8.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.22.4)': + dependencies: + big.js: 6.2.2 + dayjs: 1.11.13 + viem: 2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.22.4) + transitivePeerDependencies: + - bufferutil + - typescript + - utf-8-validate + - zod + + '@reown/appkit-common@1.8.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)': + dependencies: + big.js: 6.2.2 + dayjs: 1.11.13 + viem: 2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + transitivePeerDependencies: + - bufferutil + - typescript + - utf-8-validate + - zod + + '@reown/appkit-controllers@1.7.8(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@reown/appkit-common': 1.7.8(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-wallet': 1.7.8(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) + '@walletconnect/universal-provider': 2.21.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + valtio: 1.13.2(@types/react@19.2.7)(react@19.2.3) + viem: 2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - zod + + '@reown/appkit-controllers@1.7.8(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)': + dependencies: + '@reown/appkit-common': 1.7.8(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@reown/appkit-wallet': 1.7.8(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) + '@walletconnect/universal-provider': 2.21.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + valtio: 1.13.2(@types/react@19.2.7)(react@19.2.3) + viem: 2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - zod + optional: true + + '@reown/appkit-controllers@1.8.9(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)': + dependencies: + '@reown/appkit-common': 1.8.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@reown/appkit-wallet': 1.8.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) + '@walletconnect/universal-provider': 2.21.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + valtio: 2.1.7(@types/react@19.2.7)(react@19.2.3) + viem: 2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - zod + + '@reown/appkit-pay@1.7.8(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@reown/appkit-common': 1.7.8(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-controllers': 1.7.8(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-ui': 1.7.8(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-utils': 1.7.8(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.2.7)(react@19.2.3))(zod@3.25.76) + lit: 3.3.0 + valtio: 1.13.2(@types/react@19.2.7)(react@19.2.3) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - zod + + '@reown/appkit-pay@1.7.8(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)': + dependencies: + '@reown/appkit-common': 1.7.8(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@reown/appkit-controllers': 1.7.8(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@reown/appkit-ui': 1.7.8(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@reown/appkit-utils': 1.7.8(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.2.7)(react@19.2.3))(zod@4.2.1) + lit: 3.3.0 + valtio: 1.13.2(@types/react@19.2.7)(react@19.2.3) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - zod + optional: true + + '@reown/appkit-pay@1.8.9(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)': + dependencies: + '@reown/appkit-common': 1.8.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@reown/appkit-controllers': 1.8.9(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@reown/appkit-ui': 1.8.9(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@reown/appkit-utils': 1.8.9(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(valtio@2.1.7(@types/react@19.2.7)(react@19.2.3))(zod@4.2.1) + lit: 3.3.0 + valtio: 2.1.7(@types/react@19.2.7)(react@19.2.3) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - zod + + '@reown/appkit-polyfills@1.7.8': + dependencies: + buffer: 6.0.3 + + '@reown/appkit-polyfills@1.8.9': + dependencies: + buffer: 6.0.3 + + '@reown/appkit-scaffold-ui@1.7.8(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.2.7)(react@19.2.3))(zod@3.25.76)': + dependencies: + '@reown/appkit-common': 1.7.8(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-controllers': 1.7.8(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-ui': 1.7.8(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-utils': 1.7.8(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.2.7)(react@19.2.3))(zod@3.25.76) + '@reown/appkit-wallet': 1.7.8(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) + lit: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - valtio + - zod + + '@reown/appkit-scaffold-ui@1.7.8(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.2.7)(react@19.2.3))(zod@4.2.1)': + dependencies: + '@reown/appkit-common': 1.7.8(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@reown/appkit-controllers': 1.7.8(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@reown/appkit-ui': 1.7.8(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@reown/appkit-utils': 1.7.8(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.2.7)(react@19.2.3))(zod@4.2.1) + '@reown/appkit-wallet': 1.7.8(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) + lit: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - valtio + - zod + optional: true + + '@reown/appkit-scaffold-ui@1.8.9(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(valtio@2.1.7(@types/react@19.2.7)(react@19.2.3))(zod@4.2.1)': + dependencies: + '@reown/appkit-common': 1.8.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@reown/appkit-controllers': 1.8.9(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@reown/appkit-ui': 1.8.9(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@reown/appkit-utils': 1.8.9(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(valtio@2.1.7(@types/react@19.2.7)(react@19.2.3))(zod@4.2.1) + '@reown/appkit-wallet': 1.8.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) + lit: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - valtio + - zod + + '@reown/appkit-ui@1.7.8(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@reown/appkit-common': 1.7.8(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-controllers': 1.7.8(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-wallet': 1.7.8(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) + lit: 3.3.0 + qrcode: 1.5.3 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - zod + + '@reown/appkit-ui@1.7.8(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)': + dependencies: + '@reown/appkit-common': 1.7.8(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@reown/appkit-controllers': 1.7.8(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@reown/appkit-wallet': 1.7.8(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) + lit: 3.3.0 + qrcode: 1.5.3 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - zod + optional: true + + '@reown/appkit-ui@1.8.9(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)': + dependencies: + '@phosphor-icons/webcomponents': 2.1.5 + '@reown/appkit-common': 1.8.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@reown/appkit-controllers': 1.8.9(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@reown/appkit-wallet': 1.8.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) + lit: 3.3.0 + qrcode: 1.5.3 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - zod + + '@reown/appkit-utils@1.7.8(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.2.7)(react@19.2.3))(zod@3.25.76)': + dependencies: + '@reown/appkit-common': 1.7.8(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-controllers': 1.7.8(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-polyfills': 1.7.8 + '@reown/appkit-wallet': 1.7.8(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) + '@walletconnect/logger': 2.1.2 + '@walletconnect/universal-provider': 2.21.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + valtio: 1.13.2(@types/react@19.2.7)(react@19.2.3) + viem: 2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - zod + + '@reown/appkit-utils@1.7.8(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.2.7)(react@19.2.3))(zod@4.2.1)': + dependencies: + '@reown/appkit-common': 1.7.8(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@reown/appkit-controllers': 1.7.8(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@reown/appkit-polyfills': 1.7.8 + '@reown/appkit-wallet': 1.7.8(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) + '@walletconnect/logger': 2.1.2 + '@walletconnect/universal-provider': 2.21.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + valtio: 1.13.2(@types/react@19.2.7)(react@19.2.3) + viem: 2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - zod + optional: true + + '@reown/appkit-utils@1.8.9(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(valtio@2.1.7(@types/react@19.2.7)(react@19.2.3))(zod@4.2.1)': + dependencies: + '@reown/appkit-common': 1.8.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@reown/appkit-controllers': 1.8.9(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@reown/appkit-polyfills': 1.8.9 + '@reown/appkit-wallet': 1.8.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) + '@wallet-standard/wallet': 1.1.0 + '@walletconnect/logger': 2.1.2 + '@walletconnect/universal-provider': 2.21.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + valtio: 2.1.7(@types/react@19.2.7)(react@19.2.3) + viem: 2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - zod + + '@reown/appkit-wallet@1.7.8(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)': + dependencies: + '@reown/appkit-common': 1.7.8(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.22.4) + '@reown/appkit-polyfills': 1.7.8 + '@walletconnect/logger': 2.1.2 + zod: 3.22.4 + transitivePeerDependencies: + - bufferutil + - typescript + - utf-8-validate + + '@reown/appkit-wallet@1.8.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)': + dependencies: + '@reown/appkit-common': 1.8.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.22.4) + '@reown/appkit-polyfills': 1.8.9 + '@walletconnect/logger': 2.1.2 + zod: 3.22.4 + transitivePeerDependencies: + - bufferutil + - typescript + - utf-8-validate + + '@reown/appkit@1.7.8(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@reown/appkit-common': 1.7.8(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-controllers': 1.7.8(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-pay': 1.7.8(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-polyfills': 1.7.8 + '@reown/appkit-scaffold-ui': 1.7.8(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.2.7)(react@19.2.3))(zod@3.25.76) + '@reown/appkit-ui': 1.7.8(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-utils': 1.7.8(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.2.7)(react@19.2.3))(zod@3.25.76) + '@reown/appkit-wallet': 1.7.8(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) + '@walletconnect/types': 2.21.0 + '@walletconnect/universal-provider': 2.21.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + bs58: 6.0.0 + valtio: 1.13.2(@types/react@19.2.7)(react@19.2.3) + viem: 2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - zod + + '@reown/appkit@1.7.8(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)': + dependencies: + '@reown/appkit-common': 1.7.8(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@reown/appkit-controllers': 1.7.8(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@reown/appkit-pay': 1.7.8(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@reown/appkit-polyfills': 1.7.8 + '@reown/appkit-scaffold-ui': 1.7.8(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.2.7)(react@19.2.3))(zod@4.2.1) + '@reown/appkit-ui': 1.7.8(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@reown/appkit-utils': 1.7.8(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.2.7)(react@19.2.3))(zod@4.2.1) + '@reown/appkit-wallet': 1.7.8(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) + '@walletconnect/types': 2.21.0 + '@walletconnect/universal-provider': 2.21.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + bs58: 6.0.0 + valtio: 1.13.2(@types/react@19.2.7)(react@19.2.3) + viem: 2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - zod + optional: true + + '@reown/appkit@1.8.9(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)': + dependencies: + '@reown/appkit-common': 1.8.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@reown/appkit-controllers': 1.8.9(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@reown/appkit-pay': 1.8.9(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@reown/appkit-polyfills': 1.8.9 + '@reown/appkit-scaffold-ui': 1.8.9(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(valtio@2.1.7(@types/react@19.2.7)(react@19.2.3))(zod@4.2.1) + '@reown/appkit-ui': 1.8.9(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@reown/appkit-utils': 1.8.9(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(valtio@2.1.7(@types/react@19.2.7)(react@19.2.3))(zod@4.2.1) + '@reown/appkit-wallet': 1.8.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) + '@walletconnect/universal-provider': 2.21.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + bs58: 6.0.0 + semver: 7.7.2 + valtio: 2.1.7(@types/react@19.2.7)(react@19.2.3) + viem: 2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + optionalDependencies: + '@lit/react': 1.0.8(@types/react@19.2.7) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - zod + + '@rolldown/binding-android-arm64@1.0.0-beta.53': + optional: true + + '@rolldown/binding-darwin-arm64@1.0.0-beta.53': + optional: true + + '@rolldown/binding-darwin-x64@1.0.0-beta.53': + optional: true + + '@rolldown/binding-freebsd-x64@1.0.0-beta.53': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.53': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.53': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.0.0-beta.53': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.0.0-beta.53': + optional: true + + '@rolldown/binding-linux-x64-musl@1.0.0-beta.53': + optional: true + + '@rolldown/binding-openharmony-arm64@1.0.0-beta.53': + optional: true + + '@rolldown/binding-wasm32-wasi@1.0.0-beta.53': + dependencies: + '@napi-rs/wasm-runtime': 1.1.0 + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.53': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.0.0-beta.53': + optional: true + + '@rolldown/pluginutils@1.0.0-beta.53': {} + + '@safe-global/safe-apps-provider@0.18.6(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + events: 3.3.0 + transitivePeerDependencies: + - bufferutil + - typescript + - utf-8-validate + - zod + + '@safe-global/safe-apps-provider@0.18.6(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)': + dependencies: + '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + events: 3.3.0 + transitivePeerDependencies: + - bufferutil + - typescript + - utf-8-validate + - zod + optional: true + + '@safe-global/safe-apps-sdk@9.1.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@safe-global/safe-gateway-typescript-sdk': 3.23.1 + viem: 2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + transitivePeerDependencies: + - bufferutil + - typescript + - utf-8-validate + - zod + + '@safe-global/safe-apps-sdk@9.1.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)': + dependencies: + '@safe-global/safe-gateway-typescript-sdk': 3.23.1 + viem: 2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + transitivePeerDependencies: + - bufferutil + - typescript + - utf-8-validate + - zod + optional: true + + '@safe-global/safe-gateway-typescript-sdk@3.23.1': {} + + '@scure/base@1.1.9': {} + + '@scure/base@1.2.6': {} + + '@scure/bip32@1.4.0': + dependencies: + '@noble/curves': 1.4.2 + '@noble/hashes': 1.4.0 + '@scure/base': 1.1.9 + + '@scure/bip32@1.6.2': + dependencies: + '@noble/curves': 1.8.1 + '@noble/hashes': 1.7.1 + '@scure/base': 1.2.6 + + '@scure/bip32@1.7.0': + dependencies: + '@noble/curves': 1.9.1 + '@noble/hashes': 1.8.0 + '@scure/base': 1.2.6 + + '@scure/bip39@1.3.0': + dependencies: + '@noble/hashes': 1.4.0 + '@scure/base': 1.1.9 + + '@scure/bip39@1.5.4': + dependencies: + '@noble/hashes': 1.7.1 + '@scure/base': 1.2.6 + + '@scure/bip39@1.6.0': + dependencies: + '@noble/hashes': 1.8.0 + '@scure/base': 1.2.6 + + '@simplewebauthn/browser@13.2.2': {} + + '@socket.io/component-emitter@3.1.2': {} + + '@solana-program/compute-budget@0.11.0(@solana/kit@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10)))': + dependencies: + '@solana/kit': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + + '@solana-program/system@0.8.1(@solana/kit@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10)))': + dependencies: + '@solana/kit': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + + '@solana-program/system@0.8.1(@solana/kit@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10)))': + dependencies: + '@solana/kit': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + optional: true + + '@solana-program/token-2022@0.6.1(@solana/kit@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10)))(@solana/sysvars@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))': + dependencies: + '@solana/kit': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + '@solana/sysvars': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + + '@solana-program/token@0.6.0(@solana/kit@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10)))': + dependencies: + '@solana/kit': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + + '@solana-program/token@0.9.0(@solana/kit@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10)))': + dependencies: + '@solana/kit': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + + '@solana/accounts@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 3.0.3(typescript@5.9.3) + '@solana/codecs-strings': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 3.0.3(typescript@5.9.3) + '@solana/rpc-spec': 3.0.3(typescript@5.9.3) + '@solana/rpc-types': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/accounts@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 5.1.0(typescript@5.9.3) + '@solana/codecs-strings': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 5.1.0(typescript@5.9.3) + '@solana/rpc-spec': 5.1.0(typescript@5.9.3) + '@solana/rpc-types': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/addresses@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/assertions': 3.0.3(typescript@5.9.3) + '@solana/codecs-core': 3.0.3(typescript@5.9.3) + '@solana/codecs-strings': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 3.0.3(typescript@5.9.3) + '@solana/nominal-types': 3.0.3(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/addresses@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/assertions': 5.1.0(typescript@5.9.3) + '@solana/codecs-core': 5.1.0(typescript@5.9.3) + '@solana/codecs-strings': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 5.1.0(typescript@5.9.3) + '@solana/nominal-types': 5.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/assertions@3.0.3(typescript@5.9.3)': + dependencies: + '@solana/errors': 3.0.3(typescript@5.9.3) + typescript: 5.9.3 + + '@solana/assertions@5.1.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 5.1.0(typescript@5.9.3) + typescript: 5.9.3 + + '@solana/buffer-layout@4.0.1': + dependencies: + buffer: 6.0.3 + + '@solana/codecs-core@2.3.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 2.3.0(typescript@5.9.3) + typescript: 5.9.3 + + '@solana/codecs-core@3.0.3(typescript@5.9.3)': + dependencies: + '@solana/errors': 3.0.3(typescript@5.9.3) + typescript: 5.9.3 + + '@solana/codecs-core@5.1.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 5.1.0(typescript@5.9.3) + typescript: 5.9.3 + + '@solana/codecs-data-structures@3.0.3(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 3.0.3(typescript@5.9.3) + '@solana/codecs-numbers': 3.0.3(typescript@5.9.3) + '@solana/errors': 3.0.3(typescript@5.9.3) + typescript: 5.9.3 + + '@solana/codecs-data-structures@5.1.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 5.1.0(typescript@5.9.3) + '@solana/codecs-numbers': 5.1.0(typescript@5.9.3) + '@solana/errors': 5.1.0(typescript@5.9.3) + typescript: 5.9.3 + + '@solana/codecs-numbers@2.3.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 2.3.0(typescript@5.9.3) + '@solana/errors': 2.3.0(typescript@5.9.3) + typescript: 5.9.3 + + '@solana/codecs-numbers@3.0.3(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 3.0.3(typescript@5.9.3) + '@solana/errors': 3.0.3(typescript@5.9.3) + typescript: 5.9.3 + + '@solana/codecs-numbers@5.1.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 5.1.0(typescript@5.9.3) + '@solana/errors': 5.1.0(typescript@5.9.3) + typescript: 5.9.3 + + '@solana/codecs-strings@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 3.0.3(typescript@5.9.3) + '@solana/codecs-numbers': 3.0.3(typescript@5.9.3) + '@solana/errors': 3.0.3(typescript@5.9.3) + fastestsmallesttextencoderdecoder: 1.0.22 + typescript: 5.9.3 + + '@solana/codecs-strings@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 5.1.0(typescript@5.9.3) + '@solana/codecs-numbers': 5.1.0(typescript@5.9.3) + '@solana/errors': 5.1.0(typescript@5.9.3) + typescript: 5.9.3 + optionalDependencies: + fastestsmallesttextencoderdecoder: 1.0.22 + + '@solana/codecs@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 3.0.3(typescript@5.9.3) + '@solana/codecs-data-structures': 3.0.3(typescript@5.9.3) + '@solana/codecs-numbers': 3.0.3(typescript@5.9.3) + '@solana/codecs-strings': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/options': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/codecs@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 5.1.0(typescript@5.9.3) + '@solana/codecs-data-structures': 5.1.0(typescript@5.9.3) + '@solana/codecs-numbers': 5.1.0(typescript@5.9.3) + '@solana/codecs-strings': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/options': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/errors@2.3.0(typescript@5.9.3)': + dependencies: + chalk: 5.6.2 + commander: 14.0.2 + typescript: 5.9.3 + + '@solana/errors@3.0.3(typescript@5.9.3)': + dependencies: + chalk: 5.6.2 + commander: 14.0.0 + typescript: 5.9.3 + + '@solana/errors@5.1.0(typescript@5.9.3)': + dependencies: + chalk: 5.6.2 + commander: 14.0.2 + typescript: 5.9.3 + + '@solana/fast-stable-stringify@3.0.3(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + + '@solana/fast-stable-stringify@5.1.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + + '@solana/functional@3.0.3(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + + '@solana/functional@5.1.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + + '@solana/instruction-plans@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/errors': 3.0.3(typescript@5.9.3) + '@solana/instructions': 3.0.3(typescript@5.9.3) + '@solana/promises': 3.0.3(typescript@5.9.3) + '@solana/transaction-messages': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/instruction-plans@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/errors': 5.1.0(typescript@5.9.3) + '@solana/instructions': 5.1.0(typescript@5.9.3) + '@solana/keys': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/promises': 5.1.0(typescript@5.9.3) + '@solana/transaction-messages': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/instructions@3.0.3(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 3.0.3(typescript@5.9.3) + '@solana/errors': 3.0.3(typescript@5.9.3) + typescript: 5.9.3 + + '@solana/instructions@5.1.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 5.1.0(typescript@5.9.3) + '@solana/errors': 5.1.0(typescript@5.9.3) + typescript: 5.9.3 + + '@solana/keys@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/assertions': 3.0.3(typescript@5.9.3) + '@solana/codecs-core': 3.0.3(typescript@5.9.3) + '@solana/codecs-strings': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 3.0.3(typescript@5.9.3) + '@solana/nominal-types': 3.0.3(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/keys@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/assertions': 5.1.0(typescript@5.9.3) + '@solana/codecs-core': 5.1.0(typescript@5.9.3) + '@solana/codecs-strings': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 5.1.0(typescript@5.9.3) + '@solana/nominal-types': 5.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/kit@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10))': + dependencies: + '@solana/accounts': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/addresses': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 3.0.3(typescript@5.9.3) + '@solana/functional': 3.0.3(typescript@5.9.3) + '@solana/instruction-plans': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/instructions': 3.0.3(typescript@5.9.3) + '@solana/keys': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/programs': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-parsed-types': 3.0.3(typescript@5.9.3) + '@solana/rpc-spec-types': 3.0.3(typescript@5.9.3) + '@solana/rpc-subscriptions': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + '@solana/rpc-types': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/signers': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/sysvars': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-confirmation': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + '@solana/transaction-messages': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - ws + + '@solana/kit@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10))': + dependencies: + '@solana/accounts': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/addresses': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 5.1.0(typescript@5.9.3) + '@solana/functional': 5.1.0(typescript@5.9.3) + '@solana/instruction-plans': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/instructions': 5.1.0(typescript@5.9.3) + '@solana/keys': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/offchain-messages': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/programs': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-parsed-types': 5.1.0(typescript@5.9.3) + '@solana/rpc-spec-types': 5.1.0(typescript@5.9.3) + '@solana/rpc-subscriptions': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + '@solana/rpc-types': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/signers': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/sysvars': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-confirmation': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + '@solana/transaction-messages': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - ws + + '@solana/nominal-types@3.0.3(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + + '@solana/nominal-types@5.1.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + + '@solana/offchain-messages@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 5.1.0(typescript@5.9.3) + '@solana/codecs-data-structures': 5.1.0(typescript@5.9.3) + '@solana/codecs-numbers': 5.1.0(typescript@5.9.3) + '@solana/codecs-strings': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 5.1.0(typescript@5.9.3) + '@solana/keys': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/nominal-types': 5.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/options@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 3.0.3(typescript@5.9.3) + '@solana/codecs-data-structures': 3.0.3(typescript@5.9.3) + '@solana/codecs-numbers': 3.0.3(typescript@5.9.3) + '@solana/codecs-strings': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 3.0.3(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/options@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 5.1.0(typescript@5.9.3) + '@solana/codecs-data-structures': 5.1.0(typescript@5.9.3) + '@solana/codecs-numbers': 5.1.0(typescript@5.9.3) + '@solana/codecs-strings': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 5.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/programs@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 3.0.3(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/programs@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 5.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/promises@3.0.3(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + + '@solana/promises@5.1.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + + '@solana/rpc-api@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 3.0.3(typescript@5.9.3) + '@solana/codecs-strings': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 3.0.3(typescript@5.9.3) + '@solana/keys': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-parsed-types': 3.0.3(typescript@5.9.3) + '@solana/rpc-spec': 3.0.3(typescript@5.9.3) + '@solana/rpc-transformers': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-types': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-messages': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc-api@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 5.1.0(typescript@5.9.3) + '@solana/codecs-strings': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 5.1.0(typescript@5.9.3) + '@solana/keys': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-parsed-types': 5.1.0(typescript@5.9.3) + '@solana/rpc-spec': 5.1.0(typescript@5.9.3) + '@solana/rpc-transformers': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-types': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-messages': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc-parsed-types@3.0.3(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + + '@solana/rpc-parsed-types@5.1.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + + '@solana/rpc-spec-types@3.0.3(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + + '@solana/rpc-spec-types@5.1.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + + '@solana/rpc-spec@3.0.3(typescript@5.9.3)': + dependencies: + '@solana/errors': 3.0.3(typescript@5.9.3) + '@solana/rpc-spec-types': 3.0.3(typescript@5.9.3) + typescript: 5.9.3 + + '@solana/rpc-spec@5.1.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 5.1.0(typescript@5.9.3) + '@solana/rpc-spec-types': 5.1.0(typescript@5.9.3) + typescript: 5.9.3 + + '@solana/rpc-subscriptions-api@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/keys': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 3.0.3(typescript@5.9.3) + '@solana/rpc-transformers': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-types': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-messages': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc-subscriptions-api@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/keys': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 5.1.0(typescript@5.9.3) + '@solana/rpc-transformers': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-types': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-messages': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc-subscriptions-channel-websocket@3.0.3(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10))': + dependencies: + '@solana/errors': 3.0.3(typescript@5.9.3) + '@solana/functional': 3.0.3(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 3.0.3(typescript@5.9.3) + '@solana/subscribable': 3.0.3(typescript@5.9.3) + typescript: 5.9.3 + ws: 8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10) + + '@solana/rpc-subscriptions-channel-websocket@5.1.0(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10))': + dependencies: + '@solana/errors': 5.1.0(typescript@5.9.3) + '@solana/functional': 5.1.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 5.1.0(typescript@5.9.3) + '@solana/subscribable': 5.1.0(typescript@5.9.3) + typescript: 5.9.3 + optionalDependencies: + ws: 8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10) + + '@solana/rpc-subscriptions-spec@3.0.3(typescript@5.9.3)': + dependencies: + '@solana/errors': 3.0.3(typescript@5.9.3) + '@solana/promises': 3.0.3(typescript@5.9.3) + '@solana/rpc-spec-types': 3.0.3(typescript@5.9.3) + '@solana/subscribable': 3.0.3(typescript@5.9.3) + typescript: 5.9.3 + + '@solana/rpc-subscriptions-spec@5.1.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 5.1.0(typescript@5.9.3) + '@solana/promises': 5.1.0(typescript@5.9.3) + '@solana/rpc-spec-types': 5.1.0(typescript@5.9.3) + '@solana/subscribable': 5.1.0(typescript@5.9.3) + typescript: 5.9.3 + + '@solana/rpc-subscriptions@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10))': + dependencies: + '@solana/errors': 3.0.3(typescript@5.9.3) + '@solana/fast-stable-stringify': 3.0.3(typescript@5.9.3) + '@solana/functional': 3.0.3(typescript@5.9.3) + '@solana/promises': 3.0.3(typescript@5.9.3) + '@solana/rpc-spec-types': 3.0.3(typescript@5.9.3) + '@solana/rpc-subscriptions-api': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-subscriptions-channel-websocket': 3.0.3(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + '@solana/rpc-subscriptions-spec': 3.0.3(typescript@5.9.3) + '@solana/rpc-transformers': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-types': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/subscribable': 3.0.3(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - ws + + '@solana/rpc-subscriptions@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10))': + dependencies: + '@solana/errors': 5.1.0(typescript@5.9.3) + '@solana/fast-stable-stringify': 5.1.0(typescript@5.9.3) + '@solana/functional': 5.1.0(typescript@5.9.3) + '@solana/promises': 5.1.0(typescript@5.9.3) + '@solana/rpc-spec-types': 5.1.0(typescript@5.9.3) + '@solana/rpc-subscriptions-api': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-subscriptions-channel-websocket': 5.1.0(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + '@solana/rpc-subscriptions-spec': 5.1.0(typescript@5.9.3) + '@solana/rpc-transformers': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-types': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/subscribable': 5.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - ws + + '@solana/rpc-transformers@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/errors': 3.0.3(typescript@5.9.3) + '@solana/functional': 3.0.3(typescript@5.9.3) + '@solana/nominal-types': 3.0.3(typescript@5.9.3) + '@solana/rpc-spec-types': 3.0.3(typescript@5.9.3) + '@solana/rpc-types': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc-transformers@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/errors': 5.1.0(typescript@5.9.3) + '@solana/functional': 5.1.0(typescript@5.9.3) + '@solana/nominal-types': 5.1.0(typescript@5.9.3) + '@solana/rpc-spec-types': 5.1.0(typescript@5.9.3) + '@solana/rpc-types': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc-transport-http@3.0.3(typescript@5.9.3)': + dependencies: + '@solana/errors': 3.0.3(typescript@5.9.3) + '@solana/rpc-spec': 3.0.3(typescript@5.9.3) + '@solana/rpc-spec-types': 3.0.3(typescript@5.9.3) + typescript: 5.9.3 + undici-types: 7.16.0 + + '@solana/rpc-transport-http@5.1.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 5.1.0(typescript@5.9.3) + '@solana/rpc-spec': 5.1.0(typescript@5.9.3) + '@solana/rpc-spec-types': 5.1.0(typescript@5.9.3) + typescript: 5.9.3 + undici-types: 7.16.0 + + '@solana/rpc-types@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 3.0.3(typescript@5.9.3) + '@solana/codecs-numbers': 3.0.3(typescript@5.9.3) + '@solana/codecs-strings': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 3.0.3(typescript@5.9.3) + '@solana/nominal-types': 3.0.3(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc-types@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 5.1.0(typescript@5.9.3) + '@solana/codecs-numbers': 5.1.0(typescript@5.9.3) + '@solana/codecs-strings': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 5.1.0(typescript@5.9.3) + '@solana/nominal-types': 5.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/errors': 3.0.3(typescript@5.9.3) + '@solana/fast-stable-stringify': 3.0.3(typescript@5.9.3) + '@solana/functional': 3.0.3(typescript@5.9.3) + '@solana/rpc-api': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-spec': 3.0.3(typescript@5.9.3) + '@solana/rpc-spec-types': 3.0.3(typescript@5.9.3) + '@solana/rpc-transformers': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-transport-http': 3.0.3(typescript@5.9.3) + '@solana/rpc-types': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/errors': 5.1.0(typescript@5.9.3) + '@solana/fast-stable-stringify': 5.1.0(typescript@5.9.3) + '@solana/functional': 5.1.0(typescript@5.9.3) + '@solana/rpc-api': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-spec': 5.1.0(typescript@5.9.3) + '@solana/rpc-spec-types': 5.1.0(typescript@5.9.3) + '@solana/rpc-transformers': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-transport-http': 5.1.0(typescript@5.9.3) + '@solana/rpc-types': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/signers@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 3.0.3(typescript@5.9.3) + '@solana/errors': 3.0.3(typescript@5.9.3) + '@solana/instructions': 3.0.3(typescript@5.9.3) + '@solana/keys': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/nominal-types': 3.0.3(typescript@5.9.3) + '@solana/transaction-messages': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/signers@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 5.1.0(typescript@5.9.3) + '@solana/errors': 5.1.0(typescript@5.9.3) + '@solana/instructions': 5.1.0(typescript@5.9.3) + '@solana/keys': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/nominal-types': 5.1.0(typescript@5.9.3) + '@solana/offchain-messages': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-messages': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/subscribable@3.0.3(typescript@5.9.3)': + dependencies: + '@solana/errors': 3.0.3(typescript@5.9.3) + typescript: 5.9.3 + + '@solana/subscribable@5.1.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 5.1.0(typescript@5.9.3) + typescript: 5.9.3 + + '@solana/sysvars@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/accounts': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 3.0.3(typescript@5.9.3) + '@solana/rpc-types': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/sysvars@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/accounts': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 5.1.0(typescript@5.9.3) + '@solana/rpc-types': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/transaction-confirmation@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10))': + dependencies: + '@solana/addresses': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-strings': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 3.0.3(typescript@5.9.3) + '@solana/keys': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/promises': 3.0.3(typescript@5.9.3) + '@solana/rpc': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-subscriptions': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + '@solana/rpc-types': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-messages': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - ws + + '@solana/transaction-confirmation@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10))': + dependencies: + '@solana/addresses': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-strings': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 5.1.0(typescript@5.9.3) + '@solana/keys': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/promises': 5.1.0(typescript@5.9.3) + '@solana/rpc': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-subscriptions': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + '@solana/rpc-types': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-messages': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - ws + + '@solana/transaction-messages@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 3.0.3(typescript@5.9.3) + '@solana/codecs-data-structures': 3.0.3(typescript@5.9.3) + '@solana/codecs-numbers': 3.0.3(typescript@5.9.3) + '@solana/errors': 3.0.3(typescript@5.9.3) + '@solana/functional': 3.0.3(typescript@5.9.3) + '@solana/instructions': 3.0.3(typescript@5.9.3) + '@solana/nominal-types': 3.0.3(typescript@5.9.3) + '@solana/rpc-types': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/transaction-messages@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 5.1.0(typescript@5.9.3) + '@solana/codecs-data-structures': 5.1.0(typescript@5.9.3) + '@solana/codecs-numbers': 5.1.0(typescript@5.9.3) + '@solana/errors': 5.1.0(typescript@5.9.3) + '@solana/functional': 5.1.0(typescript@5.9.3) + '@solana/instructions': 5.1.0(typescript@5.9.3) + '@solana/nominal-types': 5.1.0(typescript@5.9.3) + '@solana/rpc-types': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/transactions@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 3.0.3(typescript@5.9.3) + '@solana/codecs-data-structures': 3.0.3(typescript@5.9.3) + '@solana/codecs-numbers': 3.0.3(typescript@5.9.3) + '@solana/codecs-strings': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 3.0.3(typescript@5.9.3) + '@solana/functional': 3.0.3(typescript@5.9.3) + '@solana/instructions': 3.0.3(typescript@5.9.3) + '@solana/keys': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/nominal-types': 3.0.3(typescript@5.9.3) + '@solana/rpc-types': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-messages': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/transactions@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 5.1.0(typescript@5.9.3) + '@solana/codecs-data-structures': 5.1.0(typescript@5.9.3) + '@solana/codecs-numbers': 5.1.0(typescript@5.9.3) + '@solana/codecs-strings': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 5.1.0(typescript@5.9.3) + '@solana/functional': 5.1.0(typescript@5.9.3) + '@solana/instructions': 5.1.0(typescript@5.9.3) + '@solana/keys': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/nominal-types': 5.1.0(typescript@5.9.3) + '@solana/rpc-types': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-messages': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/wallet-standard-features@1.3.0': + dependencies: + '@wallet-standard/base': 1.1.0 + '@wallet-standard/features': 1.1.0 + + '@solana/web3.js@1.98.4(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)': + dependencies: + '@babel/runtime': 7.28.4 + '@noble/curves': 1.9.7 + '@noble/hashes': 1.4.0 + '@solana/buffer-layout': 4.0.1 + '@solana/codecs-numbers': 2.3.0(typescript@5.9.3) + agentkeepalive: 4.6.0 + bn.js: 5.2.2 + borsh: 0.7.0 + bs58: 4.0.1 + buffer: 6.0.3 + fast-stable-stringify: 1.0.0 + jayson: 4.3.0(bufferutil@4.1.0)(utf-8-validate@5.0.10) + node-fetch: 2.7.0 + rpc-websockets: 9.3.2 + superstruct: 2.0.2 + transitivePeerDependencies: + - bufferutil + - encoding + - typescript + - utf-8-validate + + '@swc/helpers@0.5.17': + dependencies: + tslib: 2.8.1 + + '@tailwindcss/node@4.1.18': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.18.4 + jiti: 2.6.1 + lightningcss: 1.30.2 + magic-string: 0.30.21 + source-map-js: 1.2.1 + tailwindcss: 4.1.18 + + '@tailwindcss/oxide-android-arm64@4.1.18': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.1.18': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.1.18': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.1.18': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.18': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.1.18': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.1.18': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.1.18': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.1.18': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.18': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.1.18': + optional: true + + '@tailwindcss/oxide@4.1.18': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.1.18 + '@tailwindcss/oxide-darwin-arm64': 4.1.18 + '@tailwindcss/oxide-darwin-x64': 4.1.18 + '@tailwindcss/oxide-freebsd-x64': 4.1.18 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.18 + '@tailwindcss/oxide-linux-arm64-gnu': 4.1.18 + '@tailwindcss/oxide-linux-arm64-musl': 4.1.18 + '@tailwindcss/oxide-linux-x64-gnu': 4.1.18 + '@tailwindcss/oxide-linux-x64-musl': 4.1.18 + '@tailwindcss/oxide-wasm32-wasi': 4.1.18 + '@tailwindcss/oxide-win32-arm64-msvc': 4.1.18 + '@tailwindcss/oxide-win32-x64-msvc': 4.1.18 + + '@tailwindcss/vite@4.1.18(rolldown-vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1))': + dependencies: + '@tailwindcss/node': 4.1.18 + '@tailwindcss/oxide': 4.1.18 + tailwindcss: 4.1.18 + vite: rolldown-vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1) + + '@tanstack/query-core@5.90.12': {} + + '@tanstack/react-query@5.90.12(react@19.2.3)': + dependencies: + '@tanstack/query-core': 5.90.12 + react: 19.2.3 + + '@tanstack/react-virtual@3.13.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@tanstack/virtual-core': 3.13.13 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@tanstack/virtual-core@3.13.13': {} + + '@tybys/wasm-util@0.10.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@types/babel__core@7.20.5': + dependencies: + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + '@types/babel__generator': 7.27.0 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.28.0 + + '@types/babel__generator@7.27.0': + dependencies: + '@babel/types': 7.28.5 + + '@types/babel__template@7.4.4': + dependencies: + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + + '@types/babel__traverse@7.28.0': + dependencies: + '@babel/types': 7.28.5 + + '@types/connect@3.4.38': + dependencies: + '@types/node': 25.0.3 + + '@types/debug@4.1.12': + dependencies: + '@types/ms': 2.1.0 + + '@types/estree@1.0.8': {} + + '@types/json-schema@7.0.15': {} + + '@types/lodash@4.17.21': {} + + '@types/ms@2.1.0': {} + + '@types/node@12.20.55': {} + + '@types/node@25.0.3': + dependencies: + undici-types: 7.16.0 + + '@types/react-dom@19.2.3(@types/react@19.2.7)': + dependencies: + '@types/react': 19.2.7 + + '@types/react@19.2.7': + dependencies: + csstype: 3.2.3 + + '@types/stylis@4.2.5': {} + + '@types/trusted-types@2.0.7': {} + + '@types/uuid@8.3.4': {} + + '@types/ws@7.4.7': + dependencies: + '@types/node': 25.0.3 + + '@types/ws@8.18.1': + dependencies: + '@types/node': 25.0.3 + + '@typescript-eslint/eslint-plugin@8.50.1(@typescript-eslint/parser@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.50.1 + '@typescript-eslint/type-utils': 8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.50.1 + eslint: 9.39.2(jiti@2.6.1) + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.50.1 + '@typescript-eslint/types': 8.50.1 + '@typescript-eslint/typescript-estree': 8.50.1(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.50.1 + debug: 4.4.3 + eslint: 9.39.2(jiti@2.6.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.50.1(typescript@5.9.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.50.1(typescript@5.9.3) + '@typescript-eslint/types': 8.50.1 + debug: 4.4.3 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.50.1': + dependencies: + '@typescript-eslint/types': 8.50.1 + '@typescript-eslint/visitor-keys': 8.50.1 + + '@typescript-eslint/tsconfig-utils@8.50.1(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + + '@typescript-eslint/type-utils@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/types': 8.50.1 + '@typescript-eslint/typescript-estree': 8.50.1(typescript@5.9.3) + '@typescript-eslint/utils': 8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + debug: 4.4.3 + eslint: 9.39.2(jiti@2.6.1) + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@8.50.1': {} + + '@typescript-eslint/typescript-estree@8.50.1(typescript@5.9.3)': + dependencies: + '@typescript-eslint/project-service': 8.50.1(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.50.1(typescript@5.9.3) + '@typescript-eslint/types': 8.50.1 + '@typescript-eslint/visitor-keys': 8.50.1 + debug: 4.4.3 + minimatch: 9.0.5 + semver: 7.7.3 + tinyglobby: 0.2.15 + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1)) + '@typescript-eslint/scope-manager': 8.50.1 + '@typescript-eslint/types': 8.50.1 + '@typescript-eslint/typescript-estree': 8.50.1(typescript@5.9.3) + eslint: 9.39.2(jiti@2.6.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.50.1': + dependencies: + '@typescript-eslint/types': 8.50.1 + eslint-visitor-keys: 4.2.1 + + '@vitejs/plugin-react@5.1.2(rolldown-vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1))': + dependencies: + '@babel/core': 7.28.5 + '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.5) + '@rolldown/pluginutils': 1.0.0-beta.53 + '@types/babel__core': 7.20.5 + react-refresh: 0.18.0 + vite: rolldown-vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1) + transitivePeerDependencies: + - supports-color + + '@wagmi/connectors@6.2.0(@tanstack/react-query@5.90.12(react@19.2.3))(@types/react@19.2.7)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.12)(@types/react@19.2.7)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)))(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(viem@2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1))(wagmi@2.19.5(@tanstack/query-core@5.90.12)(@tanstack/react-query@5.90.12(react@19.2.3))(@types/react@19.2.7)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(viem@2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1))(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)': + dependencies: + '@base-org/account': 2.4.0(@types/react@19.2.7)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76) + '@coinbase/wallet-sdk': 4.3.6(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(zod@3.25.76) + '@gemini-wallet/core': 0.3.2(viem@2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)) + '@metamask/sdk': 0.33.1(bufferutil@4.1.0)(utf-8-validate@5.0.10) + '@safe-global/safe-apps-provider': 0.18.6(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.12)(@types/react@19.2.7)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)) + '@walletconnect/ethereum-provider': 2.21.1(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + cbw-sdk: '@coinbase/wallet-sdk@3.9.3' + porto: 0.2.35(@tanstack/react-query@5.90.12(react@19.2.3))(@types/react@19.2.7)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.12)(@types/react@19.2.7)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)))(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1))(wagmi@2.19.5(@tanstack/query-core@5.90.12)(@tanstack/react-query@5.90.12(react@19.2.3))(@types/react@19.2.7)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(viem@2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1))(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)) + viem: 2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@tanstack/react-query' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - debug + - encoding + - expo-auth-session + - expo-crypto + - expo-web-browser + - fastestsmallesttextencoderdecoder + - immer + - ioredis + - react + - react-native + - supports-color + - uploadthing + - use-sync-external-store + - utf-8-validate + - wagmi + - ws + - zod + + '@wagmi/connectors@7.0.3(f96f4901bbb7f6c4a604d4b91951b399)': + dependencies: + '@wagmi/core': 3.0.1(@tanstack/query-core@5.90.12)(@types/react@19.2.7)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)) + viem: 2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + optionalDependencies: + '@base-org/account': 2.4.0(@types/react@19.2.7)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@4.2.1) + '@coinbase/wallet-sdk': 4.3.6(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(zod@4.2.1) + '@gemini-wallet/core': 0.3.2(viem@2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)) + '@metamask/sdk': 0.33.1(bufferutil@4.1.0)(utf-8-validate@5.0.10) + '@safe-global/safe-apps-provider': 0.18.6(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@walletconnect/ethereum-provider': 2.21.1(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + porto: 0.2.35(@tanstack/react-query@5.90.12(react@19.2.3))(@types/react@19.2.7)(@wagmi/core@3.0.1(@tanstack/query-core@5.90.12)(@types/react@19.2.7)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)))(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1))(wagmi@3.1.1) + typescript: 5.9.3 + + '@wagmi/core@2.22.1(@tanstack/query-core@5.90.12)(@types/react@19.2.7)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1))': + dependencies: + eventemitter3: 5.0.1 + mipd: 0.0.7(typescript@5.9.3) + viem: 2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + zustand: 5.0.0(@types/react@19.2.7)(react@19.2.3)(use-sync-external-store@1.4.0(react@19.2.3)) + optionalDependencies: + '@tanstack/query-core': 5.90.12 + typescript: 5.9.3 + transitivePeerDependencies: + - '@types/react' + - immer + - react + - use-sync-external-store + + '@wagmi/core@3.0.1(@tanstack/query-core@5.90.12)(@types/react@19.2.7)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1))': + dependencies: + eventemitter3: 5.0.1 + mipd: 0.0.7(typescript@5.9.3) + viem: 2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + zustand: 5.0.0(@types/react@19.2.7)(react@19.2.3)(use-sync-external-store@1.4.0(react@19.2.3)) + optionalDependencies: + '@tanstack/query-core': 5.90.12 + typescript: 5.9.3 + transitivePeerDependencies: + - '@types/react' + - immer + - react + - use-sync-external-store + + '@wallet-standard/app@1.1.0': + dependencies: + '@wallet-standard/base': 1.1.0 + + '@wallet-standard/base@1.1.0': {} + + '@wallet-standard/features@1.1.0': + dependencies: + '@wallet-standard/base': 1.1.0 + + '@wallet-standard/wallet@1.1.0': + dependencies: + '@wallet-standard/base': 1.1.0 + + '@walletconnect/core@2.21.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-provider': 1.0.14 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/jsonrpc-ws-connection': 1.0.16(bufferutil@4.1.0)(utf-8-validate@5.0.10) + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/logger': 2.1.2 + '@walletconnect/relay-api': 1.0.11 + '@walletconnect/relay-auth': 1.1.0 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.21.0 + '@walletconnect/utils': 2.21.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/window-getters': 1.0.1 + es-toolkit: 1.33.0 + events: 3.3.0 + uint8arrays: 3.1.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + + '@walletconnect/core@2.21.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)': + dependencies: + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-provider': 1.0.14 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/jsonrpc-ws-connection': 1.0.16(bufferutil@4.1.0)(utf-8-validate@5.0.10) + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/logger': 2.1.2 + '@walletconnect/relay-api': 1.0.11 + '@walletconnect/relay-auth': 1.1.0 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.21.0 + '@walletconnect/utils': 2.21.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@walletconnect/window-getters': 1.0.1 + es-toolkit: 1.33.0 + events: 3.3.0 + uint8arrays: 3.1.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + optional: true + + '@walletconnect/core@2.21.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-provider': 1.0.14 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/jsonrpc-ws-connection': 1.0.16(bufferutil@4.1.0)(utf-8-validate@5.0.10) + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/logger': 2.1.2 + '@walletconnect/relay-api': 1.0.11 + '@walletconnect/relay-auth': 1.1.0 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.21.1 + '@walletconnect/utils': 2.21.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/window-getters': 1.0.1 + es-toolkit: 1.33.0 + events: 3.3.0 + uint8arrays: 3.1.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + + '@walletconnect/core@2.21.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)': + dependencies: + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-provider': 1.0.14 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/jsonrpc-ws-connection': 1.0.16(bufferutil@4.1.0)(utf-8-validate@5.0.10) + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/logger': 2.1.2 + '@walletconnect/relay-api': 1.0.11 + '@walletconnect/relay-auth': 1.1.0 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.21.1 + '@walletconnect/utils': 2.21.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@walletconnect/window-getters': 1.0.1 + es-toolkit: 1.33.0 + events: 3.3.0 + uint8arrays: 3.1.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + optional: true + + '@walletconnect/core@2.21.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)': + dependencies: + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-provider': 1.0.14 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/jsonrpc-ws-connection': 1.0.16(bufferutil@4.1.0)(utf-8-validate@5.0.10) + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/logger': 2.1.2 + '@walletconnect/relay-api': 1.0.11 + '@walletconnect/relay-auth': 1.1.0 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.21.9 + '@walletconnect/utils': 2.21.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@walletconnect/window-getters': 1.0.1 + es-toolkit: 1.39.3 + events: 3.3.0 + uint8arrays: 3.1.1 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + + '@walletconnect/core@2.22.4(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)': + dependencies: + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-provider': 1.0.14 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/jsonrpc-ws-connection': 1.0.16(bufferutil@4.1.0)(utf-8-validate@5.0.10) + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/logger': 3.0.0 + '@walletconnect/relay-api': 1.0.11 + '@walletconnect/relay-auth': 1.1.0 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.22.4 + '@walletconnect/utils': 2.22.4(typescript@5.9.3)(zod@4.2.1) + '@walletconnect/window-getters': 1.0.1 + es-toolkit: 1.39.3 + events: 3.3.0 + uint8arrays: 3.1.1 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + + '@walletconnect/environment@1.0.1': + dependencies: + tslib: 1.14.1 + + '@walletconnect/ethereum-provider@2.21.1(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@reown/appkit': 1.7.8(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/jsonrpc-http-connection': 1.0.8 + '@walletconnect/jsonrpc-provider': 1.0.14 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/sign-client': 2.21.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/types': 2.21.1 + '@walletconnect/universal-provider': 2.21.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/utils': 2.21.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - zod + + '@walletconnect/ethereum-provider@2.21.1(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)': + dependencies: + '@reown/appkit': 1.7.8(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@walletconnect/jsonrpc-http-connection': 1.0.8 + '@walletconnect/jsonrpc-provider': 1.0.14 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/sign-client': 2.21.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@walletconnect/types': 2.21.1 + '@walletconnect/universal-provider': 2.21.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@walletconnect/utils': 2.21.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - zod + optional: true + + '@walletconnect/ethereum-provider@2.22.4(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)': + dependencies: + '@reown/appkit': 1.8.9(@types/react@19.2.7)(bufferutil@4.1.0)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@walletconnect/jsonrpc-http-connection': 1.0.8 + '@walletconnect/jsonrpc-provider': 1.0.14 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/logger': 3.0.0 + '@walletconnect/sign-client': 2.22.4(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@walletconnect/types': 2.22.4 + '@walletconnect/universal-provider': 2.22.4(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@walletconnect/utils': 2.22.4(typescript@5.9.3)(zod@4.2.1) + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - zod + + '@walletconnect/events@1.0.1': + dependencies: + keyvaluestorage-interface: 1.0.0 + tslib: 1.14.1 + + '@walletconnect/heartbeat@1.2.2': + dependencies: + '@walletconnect/events': 1.0.1 + '@walletconnect/time': 1.0.2 + events: 3.3.0 + + '@walletconnect/jsonrpc-http-connection@1.0.8': + dependencies: + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/safe-json': 1.0.2 + cross-fetch: 3.2.0 + events: 3.3.0 + transitivePeerDependencies: + - encoding + + '@walletconnect/jsonrpc-provider@1.0.14': + dependencies: + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/safe-json': 1.0.2 + events: 3.3.0 + + '@walletconnect/jsonrpc-types@1.0.4': + dependencies: + events: 3.3.0 + keyvaluestorage-interface: 1.0.0 + + '@walletconnect/jsonrpc-utils@1.0.8': + dependencies: + '@walletconnect/environment': 1.0.1 + '@walletconnect/jsonrpc-types': 1.0.4 + tslib: 1.14.1 + + '@walletconnect/jsonrpc-ws-connection@1.0.16(bufferutil@4.1.0)(utf-8-validate@5.0.10)': + dependencies: + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/safe-json': 1.0.2 + events: 3.3.0 + ws: 7.5.10(bufferutil@4.1.0)(utf-8-validate@5.0.10) + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@walletconnect/keyvaluestorage@1.1.1': + dependencies: + '@walletconnect/safe-json': 1.0.2 + idb-keyval: 6.2.2 + unstorage: 1.17.3(idb-keyval@6.2.2) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - db0 + - ioredis + - uploadthing + + '@walletconnect/logger@2.1.2': + dependencies: + '@walletconnect/safe-json': 1.0.2 + pino: 7.11.0 + + '@walletconnect/logger@3.0.0': + dependencies: + '@walletconnect/safe-json': 1.0.2 + pino: 10.0.0 + + '@walletconnect/relay-api@1.0.11': + dependencies: + '@walletconnect/jsonrpc-types': 1.0.4 + + '@walletconnect/relay-auth@1.1.0': + dependencies: + '@noble/curves': 1.8.0 + '@noble/hashes': 1.7.0 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + uint8arrays: 3.1.1 + + '@walletconnect/safe-json@1.0.2': + dependencies: + tslib: 1.14.1 + + '@walletconnect/sign-client@2.21.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@walletconnect/core': 2.21.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/events': 1.0.1 + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/logger': 2.1.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.21.0 + '@walletconnect/utils': 2.21.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + + '@walletconnect/sign-client@2.21.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)': + dependencies: + '@walletconnect/core': 2.21.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@walletconnect/events': 1.0.1 + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/logger': 2.1.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.21.0 + '@walletconnect/utils': 2.21.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + optional: true + + '@walletconnect/sign-client@2.21.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@walletconnect/core': 2.21.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/events': 1.0.1 + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/logger': 2.1.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.21.1 + '@walletconnect/utils': 2.21.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + + '@walletconnect/sign-client@2.21.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)': + dependencies: + '@walletconnect/core': 2.21.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@walletconnect/events': 1.0.1 + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/logger': 2.1.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.21.1 + '@walletconnect/utils': 2.21.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + optional: true + + '@walletconnect/sign-client@2.21.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)': + dependencies: + '@walletconnect/core': 2.21.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@walletconnect/events': 1.0.1 + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/logger': 2.1.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.21.9 + '@walletconnect/utils': 2.21.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + + '@walletconnect/sign-client@2.22.4(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)': + dependencies: + '@walletconnect/core': 2.22.4(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@walletconnect/events': 1.0.1 + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/logger': 3.0.0 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.22.4 + '@walletconnect/utils': 2.22.4(typescript@5.9.3)(zod@4.2.1) + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + + '@walletconnect/time@1.0.2': + dependencies: + tslib: 1.14.1 + + '@walletconnect/types@2.21.0': + dependencies: + '@walletconnect/events': 1.0.1 + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/logger': 2.1.2 + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - db0 + - ioredis + - uploadthing + + '@walletconnect/types@2.21.1': + dependencies: + '@walletconnect/events': 1.0.1 + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/logger': 2.1.2 + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - db0 + - ioredis + - uploadthing + + '@walletconnect/types@2.21.9': + dependencies: + '@walletconnect/events': 1.0.1 + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/logger': 2.1.2 + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - db0 + - ioredis + - uploadthing + + '@walletconnect/types@2.22.4': + dependencies: + '@walletconnect/events': 1.0.1 + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/logger': 3.0.0 + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - db0 + - ioredis + - uploadthing + + '@walletconnect/universal-provider@2.21.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@walletconnect/events': 1.0.1 + '@walletconnect/jsonrpc-http-connection': 1.0.8 + '@walletconnect/jsonrpc-provider': 1.0.14 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/logger': 2.1.2 + '@walletconnect/sign-client': 2.21.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/types': 2.21.0 + '@walletconnect/utils': 2.21.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + es-toolkit: 1.33.0 + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + + '@walletconnect/universal-provider@2.21.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)': + dependencies: + '@walletconnect/events': 1.0.1 + '@walletconnect/jsonrpc-http-connection': 1.0.8 + '@walletconnect/jsonrpc-provider': 1.0.14 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/logger': 2.1.2 + '@walletconnect/sign-client': 2.21.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@walletconnect/types': 2.21.0 + '@walletconnect/utils': 2.21.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + es-toolkit: 1.33.0 + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + optional: true + + '@walletconnect/universal-provider@2.21.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@walletconnect/events': 1.0.1 + '@walletconnect/jsonrpc-http-connection': 1.0.8 + '@walletconnect/jsonrpc-provider': 1.0.14 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/logger': 2.1.2 + '@walletconnect/sign-client': 2.21.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/types': 2.21.1 + '@walletconnect/utils': 2.21.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + es-toolkit: 1.33.0 + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + + '@walletconnect/universal-provider@2.21.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)': + dependencies: + '@walletconnect/events': 1.0.1 + '@walletconnect/jsonrpc-http-connection': 1.0.8 + '@walletconnect/jsonrpc-provider': 1.0.14 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/logger': 2.1.2 + '@walletconnect/sign-client': 2.21.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@walletconnect/types': 2.21.1 + '@walletconnect/utils': 2.21.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + es-toolkit: 1.33.0 + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + optional: true + + '@walletconnect/universal-provider@2.21.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)': + dependencies: + '@walletconnect/events': 1.0.1 + '@walletconnect/jsonrpc-http-connection': 1.0.8 + '@walletconnect/jsonrpc-provider': 1.0.14 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/logger': 2.1.2 + '@walletconnect/sign-client': 2.21.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@walletconnect/types': 2.21.9 + '@walletconnect/utils': 2.21.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + es-toolkit: 1.39.3 + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + + '@walletconnect/universal-provider@2.22.4(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)': + dependencies: + '@walletconnect/events': 1.0.1 + '@walletconnect/jsonrpc-http-connection': 1.0.8 + '@walletconnect/jsonrpc-provider': 1.0.14 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/logger': 3.0.0 + '@walletconnect/sign-client': 2.22.4(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + '@walletconnect/types': 2.22.4 + '@walletconnect/utils': 2.22.4(typescript@5.9.3)(zod@4.2.1) + es-toolkit: 1.39.3 + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + + '@walletconnect/utils@2.21.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@noble/ciphers': 1.2.1 + '@noble/curves': 1.8.1 + '@noble/hashes': 1.7.1 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/relay-api': 1.0.11 + '@walletconnect/relay-auth': 1.1.0 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.21.0 + '@walletconnect/window-getters': 1.0.1 + '@walletconnect/window-metadata': 1.0.1 + bs58: 6.0.0 + detect-browser: 5.3.0 + query-string: 7.1.3 + uint8arrays: 3.1.0 + viem: 2.23.2(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + + '@walletconnect/utils@2.21.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)': + dependencies: + '@noble/ciphers': 1.2.1 + '@noble/curves': 1.8.1 + '@noble/hashes': 1.7.1 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/relay-api': 1.0.11 + '@walletconnect/relay-auth': 1.1.0 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.21.0 + '@walletconnect/window-getters': 1.0.1 + '@walletconnect/window-metadata': 1.0.1 + bs58: 6.0.0 + detect-browser: 5.3.0 + query-string: 7.1.3 + uint8arrays: 3.1.0 + viem: 2.23.2(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + optional: true + + '@walletconnect/utils@2.21.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@noble/ciphers': 1.2.1 + '@noble/curves': 1.8.1 + '@noble/hashes': 1.7.1 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/relay-api': 1.0.11 + '@walletconnect/relay-auth': 1.1.0 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.21.1 + '@walletconnect/window-getters': 1.0.1 + '@walletconnect/window-metadata': 1.0.1 + bs58: 6.0.0 + detect-browser: 5.3.0 + query-string: 7.1.3 + uint8arrays: 3.1.0 + viem: 2.23.2(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + + '@walletconnect/utils@2.21.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)': + dependencies: + '@noble/ciphers': 1.2.1 + '@noble/curves': 1.8.1 + '@noble/hashes': 1.7.1 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/relay-api': 1.0.11 + '@walletconnect/relay-auth': 1.1.0 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.21.1 + '@walletconnect/window-getters': 1.0.1 + '@walletconnect/window-metadata': 1.0.1 + bs58: 6.0.0 + detect-browser: 5.3.0 + query-string: 7.1.3 + uint8arrays: 3.1.0 + viem: 2.23.2(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + optional: true + + '@walletconnect/utils@2.21.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)': + dependencies: + '@msgpack/msgpack': 3.1.2 + '@noble/ciphers': 1.3.0 + '@noble/curves': 1.9.7 + '@noble/hashes': 1.8.0 + '@scure/base': 1.2.6 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/relay-api': 1.0.11 + '@walletconnect/relay-auth': 1.1.0 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.21.9 + '@walletconnect/window-getters': 1.0.1 + '@walletconnect/window-metadata': 1.0.1 + blakejs: 1.2.1 + bs58: 6.0.0 + detect-browser: 5.3.0 + uint8arrays: 3.1.1 + viem: 2.36.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + + '@walletconnect/utils@2.22.4(typescript@5.9.3)(zod@4.2.1)': + dependencies: + '@msgpack/msgpack': 3.1.2 + '@noble/ciphers': 1.3.0 + '@noble/curves': 1.9.7 + '@noble/hashes': 1.8.0 + '@scure/base': 1.2.6 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/logger': 3.0.0 + '@walletconnect/relay-api': 1.0.11 + '@walletconnect/relay-auth': 1.1.0 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.22.4 + '@walletconnect/window-getters': 1.0.1 + '@walletconnect/window-metadata': 1.0.1 + blakejs: 1.2.1 + bs58: 6.0.0 + detect-browser: 5.3.0 + ox: 0.9.3(typescript@5.9.3)(zod@4.2.1) + uint8arrays: 3.1.1 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - db0 + - ioredis + - typescript + - uploadthing + - zod + + '@walletconnect/window-getters@1.0.1': + dependencies: + tslib: 1.14.1 + + '@walletconnect/window-metadata@1.0.1': + dependencies: + '@walletconnect/window-getters': 1.0.1 + tslib: 1.14.1 + + abitype@1.0.6(typescript@5.9.3)(zod@3.25.76): + optionalDependencies: + typescript: 5.9.3 + zod: 3.25.76 + + abitype@1.0.8(typescript@5.9.3)(zod@3.25.76): + optionalDependencies: + typescript: 5.9.3 + zod: 3.25.76 + + abitype@1.0.8(typescript@5.9.3)(zod@4.2.1): + optionalDependencies: + typescript: 5.9.3 + zod: 4.2.1 + + abitype@1.2.3(typescript@5.9.3)(zod@3.22.4): + optionalDependencies: + typescript: 5.9.3 + zod: 3.22.4 + + abitype@1.2.3(typescript@5.9.3)(zod@3.25.76): + optionalDependencies: + typescript: 5.9.3 + zod: 3.25.76 + + abitype@1.2.3(typescript@5.9.3)(zod@4.2.1): + optionalDependencies: + typescript: 5.9.3 + zod: 4.2.1 + + abort-controller@3.0.0: + dependencies: + event-target-shim: 5.0.1 + + acorn-jsx@5.3.2(acorn@8.15.0): + dependencies: + acorn: 8.15.0 + + acorn@8.15.0: {} + + agentkeepalive@4.6.0: + dependencies: + humanize-ms: 1.2.1 + + 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-regex@5.0.1: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + argparse@2.0.1: {} + + async-mutex@0.2.6: + dependencies: + tslib: 2.8.1 + + asynckit@0.4.0: {} + + atomic-sleep@1.0.0: {} + + available-typed-arrays@1.0.7: + dependencies: + possible-typed-array-names: 1.1.0 + + axios-retry@4.5.0(axios@1.13.2): + dependencies: + axios: 1.13.2 + is-retry-allowed: 2.2.0 + + axios@1.13.2: + dependencies: + follow-redirects: 1.15.11 + form-data: 4.0.5 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + + balanced-match@1.0.2: {} + + base-x@3.0.11: + dependencies: + safe-buffer: 5.2.1 + + base-x@5.0.1: {} + + base64-js@1.5.1: {} + + baseline-browser-mapping@2.9.11: {} + + big.js@6.2.2: {} + + blakejs@1.2.1: {} + + bn.js@5.2.2: {} + + borsh@0.7.0: + dependencies: + bn.js: 5.2.2 + bs58: 4.0.1 + text-encoding-utf-8: 1.0.2 + + bowser@2.13.1: {} + + brace-expansion@1.1.12: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.2: + dependencies: + balanced-match: 1.0.2 + + browserslist@4.28.1: + dependencies: + baseline-browser-mapping: 2.9.11 + caniuse-lite: 1.0.30001761 + electron-to-chromium: 1.5.267 + node-releases: 2.0.27 + update-browserslist-db: 1.2.3(browserslist@4.28.1) + + bs58@4.0.1: + dependencies: + base-x: 3.0.11 + + bs58@6.0.0: + dependencies: + base-x: 5.0.1 + + buffer@6.0.3: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + bufferutil@4.1.0: + dependencies: + node-gyp-build: 4.8.4 + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bind@1.0.8: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + get-intrinsic: 1.3.0 + set-function-length: 1.2.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + callsites@3.1.0: {} + + camelcase@5.3.1: {} + + camelize@1.0.1: {} + + caniuse-lite@1.0.30001761: {} + + canonicalize@2.1.0: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + chalk@5.6.2: {} + + charenc@0.0.2: {} + + chokidar@4.0.3: + dependencies: + readdirp: 4.1.2 + + cliui@6.0.0: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.0 + + clsx@1.2.1: {} + + clsx@2.1.1: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + colorette@2.0.20: {} + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + commander@14.0.0: {} + + commander@14.0.2: {} + + commander@2.20.3: {} + + concat-map@0.0.1: {} + + convert-source-map@2.0.0: {} + + cookie-es@1.2.2: {} + + core-util-is@1.0.3: {} + + crc-32@1.2.2: {} + + cross-fetch@3.2.0: + dependencies: + node-fetch: 2.7.0 + transitivePeerDependencies: + - encoding + + cross-fetch@4.1.0: + dependencies: + node-fetch: 2.7.0 + transitivePeerDependencies: + - encoding + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + crossws@0.3.5: + dependencies: + uncrypto: 0.1.3 + + crypt@0.0.2: {} + + css-color-keywords@1.0.0: {} + + css-to-react-native@3.2.0: + dependencies: + camelize: 1.0.1 + css-color-keywords: 1.0.0 + postcss-value-parser: 4.2.0 + + csstype@3.1.3: {} + + csstype@3.2.3: {} + + daisyui@5.5.14: {} + + date-fns@2.30.0: + dependencies: + '@babel/runtime': 7.28.4 + + dateformat@4.6.3: {} + + dayjs@1.11.13: {} + + debug@4.3.4: + dependencies: + ms: 2.1.2 + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + decamelize@1.2.0: {} + + decode-uri-component@0.2.2: {} + + deep-is@0.1.4: {} + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + + defu@6.1.4: {} + + delay@5.0.0: {} + + delayed-stream@1.0.0: {} + + derive-valtio@0.1.0(valtio@1.13.2(@types/react@19.2.7)(react@19.2.3)): + dependencies: + valtio: 1.13.2(@types/react@19.2.7)(react@19.2.3) + + destr@2.0.5: {} + + detect-browser@5.3.0: {} + + detect-libc@2.1.2: {} + + dijkstrajs@1.0.3: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + duplexify@4.1.3: + dependencies: + end-of-stream: 1.4.5 + inherits: 2.0.4 + readable-stream: 3.6.2 + stream-shift: 1.0.3 + + eciesjs@0.4.16: + dependencies: + '@ecies/ciphers': 0.2.5(@noble/ciphers@1.3.0) + '@noble/ciphers': 1.3.0 + '@noble/curves': 1.9.7 + '@noble/hashes': 1.8.0 + + electron-to-chromium@1.5.267: {} + + emoji-regex@8.0.0: {} + + encode-utf8@1.0.3: {} + + end-of-stream@1.4.5: + dependencies: + once: 1.4.0 + + engine.io-client@6.6.4(bufferutil@4.1.0)(utf-8-validate@5.0.10): + dependencies: + '@socket.io/component-emitter': 3.1.2 + debug: 4.4.3 + engine.io-parser: 5.2.3 + ws: 8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10) + xmlhttprequest-ssl: 2.1.2 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + engine.io-parser@5.2.3: {} + + enhanced-resolve@5.18.4: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.0 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + es-toolkit@1.33.0: {} + + es-toolkit@1.39.3: {} + + es6-promise@4.2.8: {} + + es6-promisify@5.0.0: + dependencies: + es6-promise: 4.2.8 + + escalade@3.2.0: {} + + escape-string-regexp@4.0.0: {} + + eslint-plugin-react-hooks@7.0.1(eslint@9.39.2(jiti@2.6.1)): + dependencies: + '@babel/core': 7.28.5 + '@babel/parser': 7.28.5 + eslint: 9.39.2(jiti@2.6.1) + hermes-parser: 0.25.1 + zod: 4.2.1 + zod-validation-error: 4.0.2(zod@4.2.1) + transitivePeerDependencies: + - supports-color + + eslint-plugin-react-refresh@0.4.26(eslint@9.39.2(jiti@2.6.1)): + dependencies: + eslint: 9.39.2(jiti@2.6.1) + + eslint-scope@8.4.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.2.1: {} + + eslint@9.39.2(jiti@2.6.1): + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1)) + '@eslint-community/regexpp': 4.12.2 + '@eslint/config-array': 0.21.1 + '@eslint/config-helpers': 0.4.2 + '@eslint/core': 0.17.0 + '@eslint/eslintrc': 3.3.3 + '@eslint/js': 9.39.2 + '@eslint/plugin-kit': 0.4.1 + '@humanfs/node': 0.16.7 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.8 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.3 + escape-string-regexp: 4.0.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + esquery: 1.6.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + optionalDependencies: + jiti: 2.6.1 + transitivePeerDependencies: + - supports-color + + espree@10.4.0: + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + eslint-visitor-keys: 4.2.1 + + esquery@1.6.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + esutils@2.0.3: {} + + eth-block-tracker@7.1.0: + dependencies: + '@metamask/eth-json-rpc-provider': 1.0.1 + '@metamask/safe-event-emitter': 3.1.2 + '@metamask/utils': 5.0.2 + json-rpc-random-id: 1.0.1 + pify: 3.0.0 + transitivePeerDependencies: + - supports-color + + eth-json-rpc-filters@6.0.1: + dependencies: + '@metamask/safe-event-emitter': 3.1.2 + async-mutex: 0.2.6 + eth-query: 2.1.2 + json-rpc-engine: 6.1.0 + pify: 5.0.0 + + eth-query@2.1.2: + dependencies: + json-rpc-random-id: 1.0.1 + xtend: 4.0.2 + + eth-rpc-errors@4.0.3: + dependencies: + fast-safe-stringify: 2.1.1 + + ethereum-cryptography@2.2.1: + dependencies: + '@noble/curves': 1.4.2 + '@noble/hashes': 1.4.0 + '@scure/bip32': 1.4.0 + '@scure/bip39': 1.3.0 + + event-target-shim@5.0.1: {} + + eventemitter2@6.4.9: {} + + eventemitter3@5.0.1: {} + + events@3.3.0: {} + + extension-port-stream@3.0.0: + dependencies: + readable-stream: 3.6.2 + webextension-polyfill: 0.10.0 + + eyes@0.1.8: {} + + fast-copy@3.0.2: {} + + fast-deep-equal@3.1.3: {} + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fast-password-entropy@1.1.1: {} + + fast-redact@3.5.0: {} + + fast-safe-stringify@2.1.1: {} + + fast-stable-stringify@1.0.0: {} + + fastestsmallesttextencoderdecoder@1.0.22: {} + + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + + fetch-retry@6.0.0: {} + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + + filter-obj@1.1.0: {} + + 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@4.0.1: + dependencies: + flatted: 3.3.3 + keyv: 4.5.4 + + flatted@3.3.3: {} + + follow-redirects@1.15.11: {} + + for-each@0.3.5: + dependencies: + is-callable: 1.2.7 + + form-data@4.0.5: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.2 + mime-types: 2.1.35 + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + generator-function@2.0.1: {} + + gensync@1.0.0-beta.2: {} + + get-caller-file@2.0.5: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + globals@14.0.0: {} + + globals@16.5.0: {} + + gopd@1.2.0: {} + + graceful-fs@4.2.11: {} + + h3@1.15.4: + dependencies: + cookie-es: 1.2.2 + crossws: 0.3.5 + defu: 6.1.4 + destr: 2.0.5 + iron-webcrypto: 1.2.1 + node-mock-http: 1.0.4 + radix3: 1.1.2 + ufo: 1.6.1 + uncrypto: 0.1.3 + + has-flag@4.0.0: {} + + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.1 + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + help-me@5.0.0: {} + + hermes-estree@0.25.1: {} + + hermes-parser@0.25.1: + dependencies: + hermes-estree: 0.25.1 + + hono@4.11.1: {} + + humanize-ms@1.2.1: + dependencies: + ms: 2.1.3 + + idb-keyval@6.2.1: {} + + idb-keyval@6.2.2: {} + + ieee754@1.2.1: {} + + ignore@5.3.2: {} + + ignore@7.0.5: {} + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + imurmurhash@0.1.4: {} + + inherits@2.0.4: {} + + iron-webcrypto@1.2.1: {} + + is-arguments@1.2.0: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-buffer@1.1.6: {} + + is-callable@1.2.7: {} + + is-extglob@2.1.1: {} + + is-fullwidth-code-point@3.0.0: {} + + is-generator-function@1.1.2: + dependencies: + call-bound: 1.0.4 + generator-function: 2.0.1 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-regex@1.2.1: + dependencies: + call-bound: 1.0.4 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + is-retry-allowed@2.2.0: {} + + is-stream@2.0.1: {} + + is-typed-array@1.1.15: + dependencies: + which-typed-array: 1.1.19 + + isarray@1.0.0: {} + + isarray@2.0.5: {} + + isexe@2.0.0: {} + + isomorphic-ws@4.0.1(ws@7.5.10(bufferutil@4.1.0)(utf-8-validate@5.0.10)): + dependencies: + ws: 7.5.10(bufferutil@4.1.0)(utf-8-validate@5.0.10) + + isows@1.0.6(ws@8.18.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)): + dependencies: + ws: 8.18.0(bufferutil@4.1.0)(utf-8-validate@5.0.10) + + isows@1.0.7(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10)): + dependencies: + ws: 8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10) + + jayson@4.3.0(bufferutil@4.1.0)(utf-8-validate@5.0.10): + dependencies: + '@types/connect': 3.4.38 + '@types/node': 12.20.55 + '@types/ws': 7.4.7 + commander: 2.20.3 + delay: 5.0.0 + es6-promisify: 5.0.0 + eyes: 0.1.8 + isomorphic-ws: 4.0.1(ws@7.5.10(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + json-stringify-safe: 5.0.1 + stream-json: 1.9.1 + uuid: 8.3.2 + ws: 7.5.10(bufferutil@4.1.0)(utf-8-validate@5.0.10) + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + jiti@2.6.1: {} + + jose@4.15.9: {} + + jose@6.1.3: {} + + joycon@3.1.1: {} + + js-cookie@3.0.5: {} + + js-tokens@4.0.0: {} + + js-yaml@4.1.1: + dependencies: + argparse: 2.0.1 + + jsesc@3.1.0: {} + + json-buffer@3.0.1: {} + + json-rpc-engine@6.1.0: + dependencies: + '@metamask/safe-event-emitter': 2.0.0 + eth-rpc-errors: 4.0.3 + + json-rpc-random-id@1.0.1: {} + + json-schema-traverse@0.4.1: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + json-stringify-safe@5.0.1: {} + + json5@2.2.3: {} + + keccak@3.0.4: + dependencies: + node-addon-api: 2.0.2 + node-gyp-build: 4.8.4 + readable-stream: 3.6.2 + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + keyvaluestorage-interface@1.0.0: {} + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + libphonenumber-js@1.12.33: {} + + lightningcss-android-arm64@1.30.2: + optional: true + + lightningcss-darwin-arm64@1.30.2: + optional: true + + lightningcss-darwin-x64@1.30.2: + optional: true + + lightningcss-freebsd-x64@1.30.2: + optional: true + + lightningcss-linux-arm-gnueabihf@1.30.2: + optional: true + + lightningcss-linux-arm64-gnu@1.30.2: + optional: true + + lightningcss-linux-arm64-musl@1.30.2: + optional: true + + lightningcss-linux-x64-gnu@1.30.2: + optional: true + + lightningcss-linux-x64-musl@1.30.2: + optional: true + + lightningcss-win32-arm64-msvc@1.30.2: + optional: true + + lightningcss-win32-x64-msvc@1.30.2: + optional: true + + lightningcss@1.30.2: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.30.2 + lightningcss-darwin-arm64: 1.30.2 + lightningcss-darwin-x64: 1.30.2 + lightningcss-freebsd-x64: 1.30.2 + lightningcss-linux-arm-gnueabihf: 1.30.2 + lightningcss-linux-arm64-gnu: 1.30.2 + lightningcss-linux-arm64-musl: 1.30.2 + lightningcss-linux-x64-gnu: 1.30.2 + lightningcss-linux-x64-musl: 1.30.2 + lightningcss-win32-arm64-msvc: 1.30.2 + lightningcss-win32-x64-msvc: 1.30.2 + + lit-element@4.2.1: + dependencies: + '@lit-labs/ssr-dom-shim': 1.4.0 + '@lit/reactive-element': 2.1.1 + lit-html: 3.3.1 + + lit-html@3.3.1: + dependencies: + '@types/trusted-types': 2.0.7 + + lit@3.3.0: + dependencies: + '@lit/reactive-element': 2.1.1 + lit-element: 4.2.1 + lit-html: 3.3.1 + + locate-path@5.0.0: + dependencies: + p-locate: 4.1.0 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.merge@4.6.2: {} + + lodash@4.17.21: {} + + lru-cache@10.4.3: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + lucide-react@0.554.0(react@19.2.3): + dependencies: + react: 19.2.3 + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + math-intrinsics@1.1.0: {} + + md5@2.3.0: + dependencies: + charenc: 0.0.2 + crypt: 0.0.2 + is-buffer: 1.1.6 + + micro-ftch@0.3.1: {} + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.12 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.2 + + minimist@1.2.8: {} + + mipd@0.0.7(typescript@5.9.3): + optionalDependencies: + typescript: 5.9.3 + + ms@2.1.2: {} + + ms@2.1.3: {} + + multiformats@9.9.0: {} + + nanoid@3.3.11: {} + + natural-compare@1.4.0: {} + + node-addon-api@2.0.2: {} + + node-fetch-native@1.6.7: {} + + node-fetch@2.7.0: + dependencies: + whatwg-url: 5.0.0 + + node-gyp-build@4.8.4: {} + + node-mock-http@1.0.4: {} + + node-releases@2.0.27: {} + + normalize-path@3.0.0: {} + + obj-multiplex@1.0.0: + dependencies: + end-of-stream: 1.4.5 + once: 1.4.0 + readable-stream: 2.3.8 + + ofetch@1.5.1: + dependencies: + destr: 2.0.5 + node-fetch-native: 1.6.7 + ufo: 1.6.1 + + on-exit-leak-free@0.2.0: {} + + on-exit-leak-free@2.1.2: {} + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + openapi-fetch@0.13.8: + dependencies: + openapi-typescript-helpers: 0.0.15 + + openapi-typescript-helpers@0.0.15: {} + + 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 + + ox@0.11.1(typescript@5.9.3)(zod@3.22.4): + dependencies: + '@adraffy/ens-normalize': 1.11.1 + '@noble/ciphers': 1.3.0 + '@noble/curves': 1.9.1 + '@noble/hashes': 1.8.0 + '@scure/bip32': 1.7.0 + '@scure/bip39': 1.6.0 + abitype: 1.2.3(typescript@5.9.3)(zod@3.22.4) + eventemitter3: 5.0.1 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - zod + + ox@0.11.1(typescript@5.9.3)(zod@3.25.76): + dependencies: + '@adraffy/ens-normalize': 1.11.1 + '@noble/ciphers': 1.3.0 + '@noble/curves': 1.9.1 + '@noble/hashes': 1.8.0 + '@scure/bip32': 1.7.0 + '@scure/bip39': 1.6.0 + abitype: 1.2.3(typescript@5.9.3)(zod@3.25.76) + eventemitter3: 5.0.1 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - zod + + ox@0.11.1(typescript@5.9.3)(zod@4.2.1): + dependencies: + '@adraffy/ens-normalize': 1.11.1 + '@noble/ciphers': 1.3.0 + '@noble/curves': 1.9.1 + '@noble/hashes': 1.8.0 + '@scure/bip32': 1.7.0 + '@scure/bip39': 1.6.0 + abitype: 1.2.3(typescript@5.9.3)(zod@4.2.1) + eventemitter3: 5.0.1 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - zod + + ox@0.6.7(typescript@5.9.3)(zod@3.25.76): + dependencies: + '@adraffy/ens-normalize': 1.11.1 + '@noble/curves': 1.8.1 + '@noble/hashes': 1.7.1 + '@scure/bip32': 1.6.2 + '@scure/bip39': 1.5.4 + abitype: 1.0.8(typescript@5.9.3)(zod@3.25.76) + eventemitter3: 5.0.1 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - zod + + ox@0.6.7(typescript@5.9.3)(zod@4.2.1): + dependencies: + '@adraffy/ens-normalize': 1.11.1 + '@noble/curves': 1.8.1 + '@noble/hashes': 1.7.1 + '@scure/bip32': 1.6.2 + '@scure/bip39': 1.5.4 + abitype: 1.0.8(typescript@5.9.3)(zod@4.2.1) + eventemitter3: 5.0.1 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - zod + optional: true + + ox@0.6.9(typescript@5.9.3)(zod@3.25.76): + dependencies: + '@adraffy/ens-normalize': 1.11.1 + '@noble/curves': 1.9.7 + '@noble/hashes': 1.8.0 + '@scure/bip32': 1.7.0 + '@scure/bip39': 1.6.0 + abitype: 1.2.3(typescript@5.9.3)(zod@3.25.76) + eventemitter3: 5.0.1 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - zod + + ox@0.6.9(typescript@5.9.3)(zod@4.2.1): + dependencies: + '@adraffy/ens-normalize': 1.11.1 + '@noble/curves': 1.9.7 + '@noble/hashes': 1.8.0 + '@scure/bip32': 1.7.0 + '@scure/bip39': 1.6.0 + abitype: 1.2.3(typescript@5.9.3)(zod@4.2.1) + eventemitter3: 5.0.1 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - zod + + ox@0.9.1(typescript@5.9.3)(zod@4.2.1): + dependencies: + '@adraffy/ens-normalize': 1.11.1 + '@noble/ciphers': 1.3.0 + '@noble/curves': 1.9.7 + '@noble/hashes': 1.8.0 + '@scure/bip32': 1.7.0 + '@scure/bip39': 1.6.0 + abitype: 1.0.8(typescript@5.9.3)(zod@4.2.1) + eventemitter3: 5.0.1 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - zod + + ox@0.9.17(typescript@5.9.3)(zod@4.2.1): + dependencies: + '@adraffy/ens-normalize': 1.11.1 + '@noble/ciphers': 1.3.0 + '@noble/curves': 1.9.1 + '@noble/hashes': 1.8.0 + '@scure/bip32': 1.7.0 + '@scure/bip39': 1.6.0 + abitype: 1.2.3(typescript@5.9.3)(zod@4.2.1) + eventemitter3: 5.0.1 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - zod + + ox@0.9.3(typescript@5.9.3)(zod@4.2.1): + dependencies: + '@adraffy/ens-normalize': 1.11.1 + '@noble/ciphers': 1.3.0 + '@noble/curves': 1.9.1 + '@noble/hashes': 1.8.0 + '@scure/bip32': 1.7.0 + '@scure/bip39': 1.6.0 + abitype: 1.2.3(typescript@5.9.3)(zod@4.2.1) + eventemitter3: 5.0.1 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - zod + + 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 + + path-exists@4.0.0: {} + + path-key@3.1.1: {} + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + picomatch@4.0.3: {} + + pify@3.0.0: {} + + pify@5.0.0: {} + + pino-abstract-transport@0.5.0: + dependencies: + duplexify: 4.1.3 + split2: 4.2.0 + + pino-abstract-transport@1.2.0: + dependencies: + readable-stream: 4.7.0 + split2: 4.2.0 + + pino-abstract-transport@2.0.0: + dependencies: + split2: 4.2.0 + + pino-pretty@10.3.1: + dependencies: + colorette: 2.0.20 + dateformat: 4.6.3 + fast-copy: 3.0.2 + fast-safe-stringify: 2.1.1 + help-me: 5.0.0 + joycon: 3.1.1 + minimist: 1.2.8 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 1.2.0 + pump: 3.0.3 + readable-stream: 4.7.0 + secure-json-parse: 2.7.0 + sonic-boom: 3.8.1 + strip-json-comments: 3.1.1 + + pino-std-serializers@4.0.0: {} + + pino-std-serializers@7.0.0: {} + + pino@10.0.0: + dependencies: + atomic-sleep: 1.0.0 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 2.0.0 + pino-std-serializers: 7.0.0 + process-warning: 5.0.0 + quick-format-unescaped: 4.0.4 + real-require: 0.2.0 + safe-stable-stringify: 2.5.0 + slow-redact: 0.3.2 + sonic-boom: 4.2.0 + thread-stream: 3.1.0 + + pino@7.11.0: + dependencies: + atomic-sleep: 1.0.0 + fast-redact: 3.5.0 + on-exit-leak-free: 0.2.0 + pino-abstract-transport: 0.5.0 + pino-std-serializers: 4.0.0 + process-warning: 1.0.0 + quick-format-unescaped: 4.0.4 + real-require: 0.1.0 + safe-stable-stringify: 2.5.0 + sonic-boom: 2.8.0 + thread-stream: 0.15.2 + + pngjs@5.0.0: {} + + pony-cause@2.1.11: {} + + porto@0.2.35(@tanstack/react-query@5.90.12(react@19.2.3))(@types/react@19.2.7)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.12)(@types/react@19.2.7)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)))(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1))(wagmi@2.19.5(@tanstack/query-core@5.90.12)(@tanstack/react-query@5.90.12(react@19.2.3))(@types/react@19.2.7)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(viem@2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1))(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)): + dependencies: + '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.12)(@types/react@19.2.7)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)) + hono: 4.11.1 + idb-keyval: 6.2.2 + mipd: 0.0.7(typescript@5.9.3) + ox: 0.9.17(typescript@5.9.3)(zod@4.2.1) + viem: 2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + zod: 4.2.1 + zustand: 5.0.9(@types/react@19.2.7)(react@19.2.3)(use-sync-external-store@1.4.0(react@19.2.3)) + optionalDependencies: + '@tanstack/react-query': 5.90.12(react@19.2.3) + react: 19.2.3 + typescript: 5.9.3 + wagmi: 2.19.5(@tanstack/query-core@5.90.12)(@tanstack/react-query@5.90.12(react@19.2.3))(@types/react@19.2.7)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(viem@2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1))(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76) + transitivePeerDependencies: + - '@types/react' + - immer + - use-sync-external-store + + porto@0.2.35(@tanstack/react-query@5.90.12(react@19.2.3))(@types/react@19.2.7)(@wagmi/core@3.0.1(@tanstack/query-core@5.90.12)(@types/react@19.2.7)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)))(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1))(wagmi@3.1.1): + dependencies: + '@wagmi/core': 3.0.1(@tanstack/query-core@5.90.12)(@types/react@19.2.7)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)) + hono: 4.11.1 + idb-keyval: 6.2.2 + mipd: 0.0.7(typescript@5.9.3) + ox: 0.9.17(typescript@5.9.3)(zod@4.2.1) + viem: 2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + zod: 4.2.1 + zustand: 5.0.9(@types/react@19.2.7)(react@19.2.3)(use-sync-external-store@1.4.0(react@19.2.3)) + optionalDependencies: + '@tanstack/react-query': 5.90.12(react@19.2.3) + react: 19.2.3 + typescript: 5.9.3 + wagmi: 3.1.1(e5a60a8fcb871a16ac1f86312b108fb9) + transitivePeerDependencies: + - '@types/react' + - immer + - use-sync-external-store + optional: true + + possible-typed-array-names@1.1.0: {} + + postcss-value-parser@4.2.0: {} + + postcss@8.4.49: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + postcss@8.5.6: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + preact@10.24.2: {} + + preact@10.28.0: {} + + prelude-ls@1.2.1: {} + + process-nextick-args@2.0.1: {} + + process-warning@1.0.0: {} + + process-warning@5.0.0: {} + + process@0.11.10: {} + + proxy-compare@2.6.0: {} + + proxy-compare@3.0.1: {} + + proxy-from-env@1.1.0: {} + + pump@3.0.3: + dependencies: + end-of-stream: 1.4.5 + once: 1.4.0 + + punycode@2.3.1: {} + + qrcode@1.5.3: + dependencies: + dijkstrajs: 1.0.3 + encode-utf8: 1.0.3 + pngjs: 5.0.0 + yargs: 15.4.1 + + qrcode@1.5.4: + dependencies: + dijkstrajs: 1.0.3 + pngjs: 5.0.0 + yargs: 15.4.1 + + query-string@7.1.3: + dependencies: + decode-uri-component: 0.2.2 + filter-obj: 1.1.0 + split-on-first: 1.1.0 + strict-uri-encode: 2.0.0 + + quick-format-unescaped@4.0.4: {} + + radix3@1.1.2: {} + + react-device-detect@2.2.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3): + dependencies: + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + ua-parser-js: 1.0.41 + + react-dom@19.2.3(react@19.2.3): + dependencies: + react: 19.2.3 + scheduler: 0.27.0 + + react-refresh@0.18.0: {} + + react@19.2.3: {} + + readable-stream@2.3.8: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + + readable-stream@4.7.0: + dependencies: + abort-controller: 3.0.0 + buffer: 6.0.3 + events: 3.3.0 + process: 0.11.10 + string_decoder: 1.3.0 + + readdirp@4.1.2: {} + + real-require@0.1.0: {} + + real-require@0.2.0: {} + + require-directory@2.1.1: {} + + require-main-filename@2.0.0: {} + + resolve-from@4.0.0: {} + + rolldown-vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1): + dependencies: + '@oxc-project/runtime': 0.101.0 + fdir: 6.5.0(picomatch@4.0.3) + lightningcss: 1.30.2 + picomatch: 4.0.3 + postcss: 8.5.6 + rolldown: 1.0.0-beta.53 + tinyglobby: 0.2.15 + optionalDependencies: + '@types/node': 25.0.3 + fsevents: 2.3.3 + jiti: 2.6.1 + + rolldown@1.0.0-beta.53: + dependencies: + '@oxc-project/types': 0.101.0 + '@rolldown/pluginutils': 1.0.0-beta.53 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.0.0-beta.53 + '@rolldown/binding-darwin-arm64': 1.0.0-beta.53 + '@rolldown/binding-darwin-x64': 1.0.0-beta.53 + '@rolldown/binding-freebsd-x64': 1.0.0-beta.53 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-beta.53 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-beta.53 + '@rolldown/binding-linux-arm64-musl': 1.0.0-beta.53 + '@rolldown/binding-linux-x64-gnu': 1.0.0-beta.53 + '@rolldown/binding-linux-x64-musl': 1.0.0-beta.53 + '@rolldown/binding-openharmony-arm64': 1.0.0-beta.53 + '@rolldown/binding-wasm32-wasi': 1.0.0-beta.53 + '@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.53 + '@rolldown/binding-win32-x64-msvc': 1.0.0-beta.53 + + rpc-websockets@9.3.2: + dependencies: + '@swc/helpers': 0.5.17 + '@types/uuid': 8.3.4 + '@types/ws': 8.18.1 + buffer: 6.0.3 + eventemitter3: 5.0.1 + uuid: 8.3.2 + ws: 8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10) + optionalDependencies: + bufferutil: 4.1.0 + utf-8-validate: 5.0.10 + + safe-buffer@5.1.2: {} + + safe-buffer@5.2.1: {} + + safe-regex-test@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-regex: 1.2.1 + + safe-stable-stringify@2.5.0: {} + + scheduler@0.27.0: {} + + secure-json-parse@2.7.0: {} + + secure-password-utilities@0.2.1: {} + + semver@6.3.1: {} + + semver@7.7.2: {} + + semver@7.7.3: {} + + set-blocking@2.0.0: {} + + set-cookie-parser@2.7.2: {} + + 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.3.0 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + + sha.js@2.4.12: + dependencies: + inherits: 2.0.4 + safe-buffer: 5.2.1 + to-buffer: 1.2.2 + + shallowequal@1.1.0: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + slow-redact@0.3.2: {} + + socket.io-client@4.8.2(bufferutil@4.1.0)(utf-8-validate@5.0.10): + dependencies: + '@socket.io/component-emitter': 3.1.2 + debug: 4.4.3 + engine.io-client: 6.6.4(bufferutil@4.1.0)(utf-8-validate@5.0.10) + socket.io-parser: 4.2.5 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + socket.io-parser@4.2.5: + dependencies: + '@socket.io/component-emitter': 3.1.2 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + sonic-boom@2.8.0: + dependencies: + atomic-sleep: 1.0.0 + + sonic-boom@3.8.1: + dependencies: + atomic-sleep: 1.0.0 + + sonic-boom@4.2.0: + dependencies: + atomic-sleep: 1.0.0 + + source-map-js@1.2.1: {} + + split-on-first@1.1.0: {} + + split2@4.2.0: {} + + stream-chain@2.2.5: {} + + stream-json@1.9.1: + dependencies: + stream-chain: 2.2.5 + + stream-shift@1.0.3: {} + + strict-uri-encode@2.0.0: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string_decoder@1.1.1: + dependencies: + safe-buffer: 5.1.2 + + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-json-comments@3.1.1: {} + + styled-components@6.1.19(react-dom@19.2.3(react@19.2.3))(react@19.2.3): + dependencies: + '@emotion/is-prop-valid': 1.2.2 + '@emotion/unitless': 0.8.1 + '@types/stylis': 4.2.5 + css-to-react-native: 3.2.0 + csstype: 3.1.3 + postcss: 8.4.49 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + shallowequal: 1.1.0 + stylis: 4.3.2 + tslib: 2.6.2 + + stylis@4.3.2: {} + + stylis@4.3.6: {} + + superstruct@1.0.4: {} + + superstruct@2.0.2: {} + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + tabbable@6.3.0: {} + + tailwindcss@4.1.18: {} + + tapable@2.3.0: {} + + text-encoding-utf-8@1.0.2: {} + + thread-stream@0.15.2: + dependencies: + real-require: 0.1.0 + + thread-stream@3.1.0: + dependencies: + real-require: 0.2.0 + + tinycolor2@1.6.0: {} + + tinyglobby@0.2.15: + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + + to-buffer@1.2.2: + dependencies: + isarray: 2.0.5 + safe-buffer: 5.2.1 + typed-array-buffer: 1.0.3 + + tr46@0.0.3: {} + + ts-api-utils@2.1.0(typescript@5.9.3): + dependencies: + typescript: 5.9.3 + + tslib@1.14.1: {} + + tslib@2.6.2: {} + + tslib@2.8.1: {} + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + typed-array-buffer@1.0.3: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-typed-array: 1.1.15 + + typescript-eslint@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): + dependencies: + '@typescript-eslint/eslint-plugin': 8.50.1(@typescript-eslint/parser@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.50.1(typescript@5.9.3) + '@typescript-eslint/utils': 8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.39.2(jiti@2.6.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + typescript@5.9.3: {} + + ua-parser-js@1.0.41: {} + + ufo@1.6.1: {} + + uint8arrays@3.1.0: + dependencies: + multiformats: 9.9.0 + + uint8arrays@3.1.1: + dependencies: + multiformats: 9.9.0 + + uncrypto@0.1.3: {} + + undici-types@7.16.0: {} + + unstorage@1.17.3(idb-keyval@6.2.2): + dependencies: + anymatch: 3.1.3 + chokidar: 4.0.3 + destr: 2.0.5 + h3: 1.15.4 + lru-cache: 10.4.3 + node-fetch-native: 1.6.7 + ofetch: 1.5.1 + ufo: 1.6.1 + optionalDependencies: + idb-keyval: 6.2.2 + + update-browserslist-db@1.2.3(browserslist@4.28.1): + dependencies: + browserslist: 4.28.1 + escalade: 3.2.0 + picocolors: 1.1.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + use-sync-external-store@1.2.0(react@19.2.3): + dependencies: + react: 19.2.3 + + use-sync-external-store@1.4.0(react@19.2.3): + dependencies: + react: 19.2.3 + + use-sync-external-store@1.6.0(react@19.2.3): + dependencies: + react: 19.2.3 + + utf-8-validate@5.0.10: + dependencies: + node-gyp-build: 4.8.4 + + util-deprecate@1.0.2: {} + + util@0.12.5: + dependencies: + inherits: 2.0.4 + is-arguments: 1.2.0 + is-generator-function: 1.1.2 + is-typed-array: 1.1.15 + which-typed-array: 1.1.19 + + uuid@8.3.2: {} + + uuid@9.0.1: {} + + valtio@1.13.2(@types/react@19.2.7)(react@19.2.3): + dependencies: + derive-valtio: 0.1.0(valtio@1.13.2(@types/react@19.2.7)(react@19.2.3)) + proxy-compare: 2.6.0 + use-sync-external-store: 1.2.0(react@19.2.3) + optionalDependencies: + '@types/react': 19.2.7 + react: 19.2.3 + + valtio@2.1.7(@types/react@19.2.7)(react@19.2.3): + dependencies: + proxy-compare: 3.0.1 + optionalDependencies: + '@types/react': 19.2.7 + react: 19.2.3 + + viem@2.23.2(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76): + dependencies: + '@noble/curves': 1.8.1 + '@noble/hashes': 1.7.1 + '@scure/bip32': 1.6.2 + '@scure/bip39': 1.5.4 + abitype: 1.0.8(typescript@5.9.3)(zod@3.25.76) + isows: 1.0.6(ws@8.18.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + ox: 0.6.7(typescript@5.9.3)(zod@3.25.76) + ws: 8.18.0(bufferutil@4.1.0)(utf-8-validate@5.0.10) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + - zod + + viem@2.23.2(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1): + dependencies: + '@noble/curves': 1.8.1 + '@noble/hashes': 1.7.1 + '@scure/bip32': 1.6.2 + '@scure/bip39': 1.5.4 + abitype: 1.0.8(typescript@5.9.3)(zod@4.2.1) + isows: 1.0.6(ws@8.18.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + ox: 0.6.7(typescript@5.9.3)(zod@4.2.1) + ws: 8.18.0(bufferutil@4.1.0)(utf-8-validate@5.0.10) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + - zod + optional: true + + viem@2.36.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1): + dependencies: + '@noble/curves': 1.9.6 + '@noble/hashes': 1.8.0 + '@scure/bip32': 1.7.0 + '@scure/bip39': 1.6.0 + abitype: 1.0.8(typescript@5.9.3)(zod@4.2.1) + isows: 1.0.7(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + ox: 0.9.1(typescript@5.9.3)(zod@4.2.1) + ws: 8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + - zod + + viem@2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.22.4): + dependencies: + '@noble/curves': 1.9.1 + '@noble/hashes': 1.8.0 + '@scure/bip32': 1.7.0 + '@scure/bip39': 1.6.0 + abitype: 1.2.3(typescript@5.9.3)(zod@3.22.4) + isows: 1.0.7(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + ox: 0.11.1(typescript@5.9.3)(zod@3.22.4) + ws: 8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + - zod + + viem@2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76): + dependencies: + '@noble/curves': 1.9.1 + '@noble/hashes': 1.8.0 + '@scure/bip32': 1.7.0 + '@scure/bip39': 1.6.0 + abitype: 1.2.3(typescript@5.9.3)(zod@3.25.76) + isows: 1.0.7(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + ox: 0.11.1(typescript@5.9.3)(zod@3.25.76) + ws: 8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + - zod + + viem@2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1): + dependencies: + '@noble/curves': 1.9.1 + '@noble/hashes': 1.8.0 + '@scure/bip32': 1.7.0 + '@scure/bip39': 1.6.0 + abitype: 1.2.3(typescript@5.9.3)(zod@4.2.1) + isows: 1.0.7(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + ox: 0.11.1(typescript@5.9.3)(zod@4.2.1) + ws: 8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + - zod + + wagmi@2.19.5(@tanstack/query-core@5.90.12)(@tanstack/react-query@5.90.12(react@19.2.3))(@types/react@19.2.7)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(viem@2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1))(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76): + dependencies: + '@tanstack/react-query': 5.90.12(react@19.2.3) + '@wagmi/connectors': 6.2.0(@tanstack/react-query@5.90.12(react@19.2.3))(@types/react@19.2.7)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.12)(@types/react@19.2.7)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)))(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(viem@2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1))(wagmi@2.19.5(@tanstack/query-core@5.90.12)(@tanstack/react-query@5.90.12(react@19.2.3))(@types/react@19.2.7)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(viem@2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1))(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76) + '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.12)(@types/react@19.2.7)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)) + react: 19.2.3 + use-sync-external-store: 1.4.0(react@19.2.3) + viem: 2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@tanstack/query-core' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - debug + - encoding + - expo-auth-session + - expo-crypto + - expo-web-browser + - fastestsmallesttextencoderdecoder + - immer + - ioredis + - react-native + - supports-color + - uploadthing + - utf-8-validate + - ws + - zod + + wagmi@3.1.1(e5a60a8fcb871a16ac1f86312b108fb9): + dependencies: + '@tanstack/react-query': 5.90.12(react@19.2.3) + '@wagmi/connectors': 7.0.3(f96f4901bbb7f6c4a604d4b91951b399) + '@wagmi/core': 3.0.1(@tanstack/query-core@5.90.12)(@types/react@19.2.7)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1)) + react: 19.2.3 + use-sync-external-store: 1.4.0(react@19.2.3) + viem: 2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - '@base-org/account' + - '@coinbase/wallet-sdk' + - '@gemini-wallet/core' + - '@metamask/sdk' + - '@safe-global/safe-apps-provider' + - '@safe-global/safe-apps-sdk' + - '@tanstack/query-core' + - '@types/react' + - '@walletconnect/ethereum-provider' + - immer + - porto + + webextension-polyfill@0.10.0: {} + + webidl-conversions@3.0.1: {} + + whatwg-url@5.0.0: + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + + which-module@2.0.1: {} + + which-typed-array@1.1.19: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + for-each: 0.3.5 + get-proto: 1.0.1 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + word-wrap@1.2.5: {} + + wrap-ansi@6.2.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrappy@1.0.2: {} + + ws@7.5.10(bufferutil@4.1.0)(utf-8-validate@5.0.10): + optionalDependencies: + bufferutil: 4.1.0 + utf-8-validate: 5.0.10 + + ws@8.18.0(bufferutil@4.1.0)(utf-8-validate@5.0.10): + optionalDependencies: + bufferutil: 4.1.0 + utf-8-validate: 5.0.10 + + ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10): + optionalDependencies: + bufferutil: 4.1.0 + utf-8-validate: 5.0.10 + + x402@0.7.3(@solana/sysvars@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3))(@tanstack/query-core@5.90.12)(@tanstack/react-query@5.90.12(react@19.2.3))(@types/react@19.2.7)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10)): + dependencies: + '@scure/base': 1.2.6 + '@solana-program/compute-budget': 0.11.0(@solana/kit@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10))) + '@solana-program/token': 0.9.0(@solana/kit@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10))) + '@solana-program/token-2022': 0.6.1(@solana/kit@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10)))(@solana/sysvars@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)) + '@solana/kit': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + '@solana/transaction-confirmation': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + '@solana/wallet-standard-features': 1.3.0 + '@wallet-standard/app': 1.1.0 + '@wallet-standard/base': 1.1.0 + '@wallet-standard/features': 1.1.0 + viem: 2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + wagmi: 2.19.5(@tanstack/query-core@5.90.12)(@tanstack/react-query@5.90.12(react@19.2.3))(@types/react@19.2.7)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(viem@2.43.3(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.2.1))(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76) + zod: 3.25.76 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@solana/sysvars' + - '@tanstack/query-core' + - '@tanstack/react-query' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - debug + - encoding + - expo-auth-session + - expo-crypto + - expo-web-browser + - fastestsmallesttextencoderdecoder + - immer + - ioredis + - react + - react-native + - supports-color + - typescript + - uploadthing + - utf-8-validate + - ws + + xmlhttprequest-ssl@2.1.2: {} + + xtend@4.0.2: {} + + y18n@4.0.3: {} + + yallist@3.1.1: {} + + yargs-parser@18.1.3: + dependencies: + camelcase: 5.3.1 + decamelize: 1.2.0 + + yargs@15.4.1: + dependencies: + cliui: 6.0.0 + decamelize: 1.2.0 + find-up: 4.1.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + require-main-filename: 2.0.0 + set-blocking: 2.0.0 + string-width: 4.2.3 + which-module: 2.0.1 + y18n: 4.0.3 + yargs-parser: 18.1.3 + + yocto-queue@0.1.0: {} + + zod-validation-error@4.0.2(zod@4.2.1): + dependencies: + zod: 4.2.1 + + zod@3.22.4: {} + + zod@3.25.76: {} + + zod@4.2.1: {} + + zustand@5.0.0(@types/react@19.2.7)(react@19.2.3)(use-sync-external-store@1.4.0(react@19.2.3)): + optionalDependencies: + '@types/react': 19.2.7 + react: 19.2.3 + use-sync-external-store: 1.4.0(react@19.2.3) + + zustand@5.0.3(@types/react@19.2.7)(react@19.2.3)(use-sync-external-store@1.4.0(react@19.2.3)): + optionalDependencies: + '@types/react': 19.2.7 + react: 19.2.3 + use-sync-external-store: 1.4.0(react@19.2.3) + + zustand@5.0.9(@types/react@19.2.7)(react@19.2.3)(use-sync-external-store@1.4.0(react@19.2.3)): + optionalDependencies: + '@types/react': 19.2.7 + react: 19.2.3 + use-sync-external-store: 1.4.0(react@19.2.3) diff --git a/ui/src/pages/UniversalDelegatorConfigurator.tsx b/ui/src/pages/UniversalDelegatorConfigurator.tsx index fe23e57b..e3daa9e1 100644 --- a/ui/src/pages/UniversalDelegatorConfigurator.tsx +++ b/ui/src/pages/UniversalDelegatorConfigurator.tsx @@ -1,128 +1,67 @@ import { usePrivy } from "@privy-io/react-auth"; import { useCallback, useEffect, useMemo, useRef, useState, type CSSProperties, type MouseEvent } from "react"; import { useAccount, usePublicClient, useReadContracts, useWaitForTransactionReceipt, useWriteContract } from "wagmi"; -import { - type Address, - BaseError, - ContractFunctionRevertedError, - type Hex, - type PublicClient, - decodeEventLog, - encodeFunctionData, - getEventSelector, - isAddress, - isHex, - padHex, -} from "viem"; +import { type Address, BaseError, type Hex, encodeFunctionData, isAddress } from "viem"; import { universalDelegatorAbi } from "../contracts/universalDelegator"; -import { createIndex, formatIndex, getChildIndex, getDepth, getParentIndex } from "../utils/universalDelegatorIndex"; - -const UNIVERSAL_DELEGATOR_EVENT_ABI = universalDelegatorAbi.filter((item) => item.type === "event") as unknown as Array< - (typeof universalDelegatorAbi)[number] ->; - -const UNIVERSAL_DELEGATOR_EVENT_TOPICS = new Set( - UNIVERSAL_DELEGATOR_EVENT_ABI.map((event) => getEventSelector(event as never)), -); - -type SlotSizeInput = string; - -type DraftState = { - draft: T; - synced: T | null; -}; - -type GroupDraft = { size: SlotSizeInput; isShared: boolean }; -type NetworkDraft = { size: SlotSizeInput; subnetwork: string }; -type OperatorDraft = { size: SlotSizeInput; operator: string }; - -type OperatorSlot = { - id: string; - index: bigint | null; - state: DraftState; -}; - -type NetworkSlot = { - id: string; - index: bigint | null; - state: DraftState; - operators: OperatorSlot[]; -}; +import { formatIndex, getChildIndex } from "../utils/universalDelegatorIndex"; +import { + type GroupConstructor, + type GroupDraft, + type GroupSlot, + type MulticallCandidate, + type NetworkDraft, + type NetworkSlot, + type OperatorDraft, + type OperatorSlot, + type UdOperation, + type UniversalDelegatorModel, + type ZoomState, + autoSyncAll, + bigintCompare, + buildMulticallCandidates, + cloneModel, + cloneOps, + compileOpsFromModels, + computePendingByIndexFromOps, + computeSimulatedAllocations, + computeSimulatedAllocationsWithPending, + computeSlotIdToIndex, + describeNotEnoughAvailable, + effectiveSize, + encodeOpsToCalls, + extractRevertName, + findFailingOp, + flexGrowFromSize, + formatOp, + formatShortAddress, + formatViemError, + maxBigint, + mergeOps, + opsBaselineModel, + opsKey, + orderMulticallCandidates, + parseBytes32, + parsePositiveInt, + parseUint, + percentWidthFromSize, + reconstructModelFromChain, + saturatingSub, + shallowOptimizeOps, + simulateMulticall, + simulateMulticallCandidates, + sumBigints, +} from "./universalDelegator/logic"; -type GroupSlot = { - id: string; - index: bigint | null; - state: DraftState; - networks: NetworkSlot[]; -}; +const FILL_OPACITY = 0.2; -type UniversalDelegatorModel = { - groups: GroupSlot[]; +type SlotMetrics = { + allocatedValue: bigint; + pendingValue: bigint; + allocatedPct: number; + pendingPct: number; }; -type ZoomState = - | { kind: "all" } - | { kind: "group"; groupId: string } - | { kind: "network"; groupId: string; networkId: string }; - -type GroupConstructor = "shared-multi" | "shared-single" | "single-multi" | "single-single"; - -type UdOperation = - | { kind: "createSlot"; parentIndex: bigint; isShared: boolean; size: bigint; slotId?: string } - | { kind: "setIsShared"; index: bigint; isShared: boolean } - | { kind: "setSize"; index: bigint; size: bigint } - | { kind: "swapSlots"; index1: bigint; index2: bigint } - | { kind: "assignNetwork"; index: bigint; subnetwork: Hex } - | { kind: "unassignNetwork"; subnetwork: Hex } - | { kind: "assignOperator"; index: bigint; operator: Address } - | { kind: "unassignOperator"; parentIndex: bigint; operator: Address }; - -function parseUint(value: string): bigint | null { - const normalized = value.trim(); - if (!normalized) return 0n; - try { - const parsed = BigInt(normalized); - if (parsed < 0n) return null; - return parsed; - } catch { - return null; - } -} - -function parseBytes32(value: string): Hex | null { - const v = value.trim(); - if (!v) return null; - - if (!v.startsWith("0x")) return null; - if (!isHex(v)) return null; - if (v.length > 66) return null; - return padHex(v, { size: 32, dir: "right" }); -} - -type HasSize = { size: SlotSizeInput }; - -function effectiveSize(state: DraftState): bigint { - const draft = parseUint(state.draft.size); - if (draft !== null) return draft; - const synced = state.synced ? parseUint(state.synced.size) : null; - return synced ?? 0n; -} - -function sumBigints(values: bigint[]): bigint { - let total = 0n; - for (const v of values) total += v; - return total; -} - -function maxBigint(values: bigint[]): bigint { - let m = 0n; - for (const v of values) if (v > m) m = v; - return m; -} - -const FILL_OPACITY = 0.2; - function pendingPatternStyle(colorVar: string): CSSProperties { const lineColor = `var(${colorVar})`; return { @@ -144,1505 +83,36 @@ function isInteractiveTarget(target: EventTarget | null): boolean { return Boolean(element.closest("button, input, textarea, select, label, a, [data-no-zoom]")); } -function formatShortAddress(address: string): string { - if (address.length <= 10) return address; - return `${address.slice(0, 6)}...${address.slice(-4)}`; -} - -function parsePositiveInt(value: string): number | null { - const trimmed = value.trim(); - if (!trimmed) return null; - const parsed = Number(trimmed); - if (!Number.isFinite(parsed) || !Number.isInteger(parsed) || parsed <= 0) return null; - return parsed; -} - -function cloneOps(values: UdOperation[]): UdOperation[] { - return values.map((op) => ({ ...op })); -} - -function cloneModel(values: UniversalDelegatorModel): UniversalDelegatorModel { - return { - groups: values.groups.map((group) => ({ - id: group.id, - index: group.index, - state: { - draft: { ...group.state.draft }, - synced: group.state.synced ? { ...group.state.synced } : null, - }, - networks: group.networks.map((network) => ({ - id: network.id, - index: network.index, - state: { - draft: { ...network.state.draft }, - synced: network.state.synced ? { ...network.state.synced } : null, - }, - operators: network.operators.map((operator) => ({ - id: operator.id, - index: operator.index, - state: { - draft: { ...operator.state.draft }, - synced: operator.state.synced ? { ...operator.state.synced } : null, - }, - })), - })), - })), - }; -} - -type OnchainSlotSnapshot = { size: bigint; isShared: boolean }; - -function latestTrace208Value(trace: unknown): bigint { - const checkpoints = (trace as { _trace?: { _checkpoints?: Array<{ _value: bigint }> } })?._trace?._checkpoints; - if (!checkpoints || checkpoints.length === 0) return 0n; - return checkpoints[checkpoints.length - 1]?._value ?? 0n; -} - -function ensureChildren(map: Map, parentIndex: bigint): bigint[] { - const existing = map.get(parentIndex); - if (existing) return existing; - const created: bigint[] = []; - map.set(parentIndex, created); - return created; -} - -function bigintMin(a: bigint, b: bigint): bigint { - return a < b ? a : b; -} - -function bigintMax(a: bigint, b: bigint): bigint { - return a > b ? a : b; -} - -function saturatingSub(a: bigint, b: bigint): bigint { - return a > b ? a - b : 0n; -} - -function computeSlotIdToIndex(model: UniversalDelegatorModel): Map { - const idToIndex = new Map(); - - let maxGroupChild = 0n; - for (const group of model.groups) { - if (group.index === null) continue; - maxGroupChild = bigintMax(maxGroupChild, getChildIndex(group.index)); - } - let nextGroupChild = maxGroupChild + 1n; - - for (const group of model.groups) { - const groupIndex = group.index ?? createIndex(0n, nextGroupChild++); - idToIndex.set(group.id, groupIndex); - - let maxNetworkChild = 0n; - for (const network of group.networks) { - if (network.index === null) continue; - maxNetworkChild = bigintMax(maxNetworkChild, getChildIndex(network.index)); - } - let nextNetworkChild = maxNetworkChild + 1n; - - for (const network of group.networks) { - const networkIndex = network.index ?? createIndex(groupIndex, nextNetworkChild++); - idToIndex.set(network.id, networkIndex); - - let maxOperatorChild = 0n; - for (const operator of network.operators) { - if (operator.index === null) continue; - maxOperatorChild = bigintMax(maxOperatorChild, getChildIndex(operator.index)); - } - let nextOperatorChild = maxOperatorChild + 1n; - - for (const operator of network.operators) { - const operatorIndex = operator.index ?? createIndex(networkIndex, nextOperatorChild++); - idToIndex.set(operator.id, operatorIndex); - } - } - } - - return idToIndex; -} - -function computeSimulatedAllocations( - model: UniversalDelegatorModel, - slotIdToIndex: Map, - rootActiveStake: bigint | null, -): Map { - const allocatedByIndex = new Map(); - const rootBalance = rootActiveStake ?? 0n; - allocatedByIndex.set("0", rootBalance); - - let groupPrevSum = 0n; - for (const group of model.groups) { - const groupSize = effectiveSize(group.state); - const groupAllocated = bigintMin(saturatingSub(rootBalance, groupPrevSum), groupSize); - const groupIndex = slotIdToIndex.get(group.id); - if (groupIndex !== undefined) allocatedByIndex.set(groupIndex.toString(), groupAllocated); - groupPrevSum += groupSize; - - const groupIsShared = group.state.draft.isShared; - let networkPrevSum = 0n; - for (const network of group.networks) { - const networkSize = effectiveSize(network.state); - const networkAllocated = groupIsShared - ? bigintMin(groupAllocated, networkSize) - : bigintMin(saturatingSub(groupAllocated, networkPrevSum), networkSize); - const networkIndex = slotIdToIndex.get(network.id); - if (networkIndex !== undefined) allocatedByIndex.set(networkIndex.toString(), networkAllocated); - networkPrevSum += networkSize; - - let operatorPrevSum = 0n; - for (const operator of network.operators) { - const operatorSize = effectiveSize(operator.state); - const operatorAllocated = bigintMin(saturatingSub(networkAllocated, operatorPrevSum), operatorSize); - const operatorIndex = slotIdToIndex.get(operator.id); - if (operatorIndex !== undefined) allocatedByIndex.set(operatorIndex.toString(), operatorAllocated); - operatorPrevSum += operatorSize; - } - } - } - - return allocatedByIndex; -} - -function computePendingByIndex(params: { - model: UniversalDelegatorModel; - slotIdToIndex: Map; - baselineSlotIdToIndex: Map; - baselineAllocationsByIndex: Map; -}): Map { - const pendingByIndex = new Map(); - const baselineAllocations = params.baselineAllocationsByIndex; - const baselineIndices = params.baselineSlotIdToIndex; - - const baselineAllocatedFor = (slotId: string): bigint => { - const baselineIndex = baselineIndices.get(slotId); - if (baselineIndex === undefined) return 0n; - return baselineAllocations.get(baselineIndex.toString()) ?? 0n; - }; - - let rootPending = 0n; - for (const group of params.model.groups) { - let groupPending = 0n; - for (const network of group.networks) { - let networkPending = 0n; - for (const operator of network.operators) { - const operatorIndex = params.slotIdToIndex.get(operator.id); - if (operatorIndex !== undefined) pendingByIndex.set(operatorIndex.toString(), 0n); - - const baselineAllocated = baselineAllocatedFor(operator.id); - const nextSize = effectiveSize(operator.state); - if (baselineAllocated > nextSize) { - networkPending += baselineAllocated - nextSize; - } - } - - const networkIndex = params.slotIdToIndex.get(network.id); - if (networkIndex !== undefined) pendingByIndex.set(networkIndex.toString(), networkPending); - - const baselineAllocated = baselineAllocatedFor(network.id); - const nextSize = effectiveSize(network.state); - if (baselineAllocated > nextSize) { - groupPending += baselineAllocated - nextSize; - } - } - - const groupIndex = params.slotIdToIndex.get(group.id); - if (groupIndex !== undefined) pendingByIndex.set(groupIndex.toString(), groupPending); - - const baselineAllocated = baselineAllocatedFor(group.id); - const nextSize = effectiveSize(group.state); - if (baselineAllocated > nextSize) { - rootPending += baselineAllocated - nextSize; - } - } - - pendingByIndex.set("0", rootPending); - return pendingByIndex; -} - -function computeSimulatedAllocationsFromStateWithPending( - state: SimState, - rootBalance: bigint, - pendingByIndex: Map, -): Map { - const allocated = new Map(); - allocated.set(0n, rootBalance); - - const walk = (parentIndex: bigint) => { - const children = state.children.get(parentIndex) ?? []; - const parentAllocated = allocated.get(parentIndex) ?? 0n; - const parentPending = pendingByIndex.get(parentIndex) ?? 0n; - const parentAvailable = saturatingSub(parentAllocated, parentPending); - const parentSlot = state.slots.get(parentIndex); - const parentIsShared = parentIndex === 0n ? false : (parentSlot?.isShared ?? false); - - let prevSum = 0n; - for (const child of children) { - const childSlot = state.slots.get(child) ?? { size: 0n, isShared: false }; - const childAllocated = parentIsShared - ? bigintMin(parentAvailable, childSlot.size) - : bigintMin(saturatingSub(parentAvailable, prevSum), childSlot.size); - allocated.set(child, childAllocated); - prevSum += childSlot.size; - walk(child); - } - }; - - walk(0n); - return allocated; -} - -function computePendingByIndexFromOps(params: { - baselineModel: UniversalDelegatorModel; - ops: UdOperation[]; - rootActiveStake: bigint | null; - baselinePendingByIndex?: Map | null; -}): Map { - if (params.ops.length === 0) return new Map(); - - const state = buildSimStateFromModel(params.baselineModel); - const pendingByIndex = new Map(); - if (params.baselinePendingByIndex) { - for (const [key, value] of params.baselinePendingByIndex.entries()) { - if (value <= 0n) continue; - try { - pendingByIndex.set(BigInt(key), value); - } catch { - // ignore invalid pending keys - } - } - } - const rootBalance = params.rootActiveStake ?? 0n; - - const addPending = (index: bigint, delta: bigint) => { - if (delta <= 0n) return; - pendingByIndex.set(index, (pendingByIndex.get(index) ?? 0n) + delta); - }; - - for (const op of params.ops) { - if (op.kind === "createSlot") { - const local = state.nextChildLocalIndex.get(op.parentIndex) ?? 1n; - let index: bigint; - try { - index = createIndex(op.parentIndex, local); - } catch { - return new Map(); - } - - state.nextChildLocalIndex.set(op.parentIndex, local + 1n); - state.created.add(index); - state.slots.set(index, { size: op.size, isShared: op.isShared }); - - if (!state.children.has(op.parentIndex)) state.children.set(op.parentIndex, []); - state.children.get(op.parentIndex)!.push(index); - if (!state.children.has(index)) state.children.set(index, []); - continue; - } - - if (op.kind === "setIsShared") { - const prev = state.slots.get(op.index) ?? { size: 0n, isShared: false }; - state.slots.set(op.index, { ...prev, isShared: op.isShared }); - continue; - } - - if (op.kind === "setSize") { - const prev = state.slots.get(op.index) ?? { size: 0n, isShared: false }; - if (op.size < prev.size) { - const allocated = computeSimulatedAllocationsFromStateWithPending(state, rootBalance, pendingByIndex); - const allocatedNow = allocated.get(op.index) ?? 0n; - if (allocatedNow > op.size) { - addPending(getParentIndex(op.index), allocatedNow - op.size); - } - } - state.slots.set(op.index, { ...prev, size: op.size }); - continue; - } - - if (op.kind === "swapSlots") { - const parent = getParentIndex(op.index1); - const list = state.children.get(parent); - if (!list) return new Map(); - const i1 = list.indexOf(op.index1); - const i2 = list.indexOf(op.index2); - if (i1 === -1 || i2 === -1) return new Map(); - [list[i1], list[i2]] = [list[i2]!, list[i1]!]; - continue; - } - - if (op.kind === "assignNetwork") { - state.networkToSlot.set(op.subnetwork.toLowerCase(), op.index); - continue; - } - - if (op.kind === "unassignNetwork") { - state.networkToSlot.set(op.subnetwork.toLowerCase(), 0n); - continue; - } - - if (op.kind === "assignOperator") { - const parentIndex = getParentIndex(op.index); - const key = `${parentIndex.toString()}:${op.operator.toLowerCase()}`; - state.operatorToSlot.set(key, op.index); - state.operatorBySlot.set(op.index, op.operator); - continue; - } - - const key = `${op.parentIndex.toString()}:${op.operator.toLowerCase()}`; - const currentIndex = state.operatorToSlot.get(key) ?? 0n; - if (currentIndex !== 0n) state.operatorBySlot.delete(currentIndex); - state.operatorToSlot.set(key, 0n); - } - - const result = new Map(); - for (const [index, value] of pendingByIndex.entries()) { - result.set(index.toString(), value); - } - return result; -} - -function computeSimulatedAllocationsWithPending(params: { - model: UniversalDelegatorModel; - slotIdToIndex: Map; - baselineSlotIdToIndex: Map; - baselineAllocationsByIndex: Map; - rootActiveStake: bigint | null; - pendingByIndexOverride?: Map | null; -}): { allocatedByIndex: Map; pendingByIndex: Map } { - const allocatedByIndex = new Map(); - const rootBalance = params.rootActiveStake ?? 0n; - const pendingByIndex = - params.pendingByIndexOverride ?? - computePendingByIndex({ - model: params.model, - slotIdToIndex: params.slotIdToIndex, - baselineSlotIdToIndex: params.baselineSlotIdToIndex, - baselineAllocationsByIndex: params.baselineAllocationsByIndex, - }); - const rootPending = pendingByIndex.get("0") ?? 0n; - const rootAvailable = saturatingSub(rootBalance, rootPending); - - allocatedByIndex.set("0", rootBalance); - - let groupPrevSum = 0n; - for (const group of params.model.groups) { - const groupSize = effectiveSize(group.state); - const groupAllocated = bigintMin(saturatingSub(rootAvailable, groupPrevSum), groupSize); - const groupIndex = params.slotIdToIndex.get(group.id); - if (groupIndex !== undefined) allocatedByIndex.set(groupIndex.toString(), groupAllocated); - groupPrevSum += groupSize; - - const groupIsShared = group.state.draft.isShared; - const groupPending = groupIndex !== undefined ? (pendingByIndex.get(groupIndex.toString()) ?? 0n) : 0n; - const groupAvailable = saturatingSub(groupAllocated, groupPending); - let networkPrevSum = 0n; - for (const network of group.networks) { - const networkSize = effectiveSize(network.state); - const networkAllocated = groupIsShared - ? bigintMin(groupAvailable, networkSize) - : bigintMin(saturatingSub(groupAvailable, networkPrevSum), networkSize); - const networkIndex = params.slotIdToIndex.get(network.id); - if (networkIndex !== undefined) allocatedByIndex.set(networkIndex.toString(), networkAllocated); - networkPrevSum += networkSize; - - const networkPending = networkIndex !== undefined ? (pendingByIndex.get(networkIndex.toString()) ?? 0n) : 0n; - const networkAvailable = saturatingSub(networkAllocated, networkPending); - let operatorPrevSum = 0n; - for (const operator of network.operators) { - const operatorSize = effectiveSize(operator.state); - const operatorAllocated = bigintMin(saturatingSub(networkAvailable, operatorPrevSum), operatorSize); - const operatorIndex = params.slotIdToIndex.get(operator.id); - if (operatorIndex !== undefined) allocatedByIndex.set(operatorIndex.toString(), operatorAllocated); - operatorPrevSum += operatorSize; - } - } - } - - return { allocatedByIndex, pendingByIndex }; -} - -async function reconstructModelFromChain(params: { - delegatorAddress: Address; - publicClient: PublicClient; -}): Promise { - const latestBlock = await params.publicClient.getBlockNumber(); - - const slots = new Map(); - const childrenByParent = new Map(); - const networkBySlot = new Map(); - const subnetworkToSlot = new Map(); - const operatorBySlot = new Map(); - - const chunkSize = 50_000n; - for (let fromBlock = 0n; fromBlock <= latestBlock; fromBlock += chunkSize) { - const toBlock = (() => { - const candidate = fromBlock + chunkSize - 1n; - return candidate > latestBlock ? latestBlock : candidate; - })(); - - const rawLogs = await params.publicClient.getLogs({ - address: params.delegatorAddress, - fromBlock, - toBlock, - }); - - for (const log of rawLogs) { - const topic0 = log.topics?.[0] as string | undefined; - if (!topic0 || !UNIVERSAL_DELEGATOR_EVENT_TOPICS.has(topic0)) continue; - - const decoded = decodeEventLog({ - abi: UNIVERSAL_DELEGATOR_EVENT_ABI as never, - data: log.data, - topics: log.topics, - }); - - if (decoded.eventName === "CreateSlot") { - const args = decoded.args as unknown as { index: bigint; size: bigint }; - const index = args.index; - const size = args.size; - slots.set(index, { size, isShared: false }); - const parentIndex = getParentIndex(index); - ensureChildren(childrenByParent, parentIndex).push(index); - continue; - } - - if (decoded.eventName === "SetSize") { - const args = decoded.args as unknown as { index: bigint; size: bigint }; - const index = args.index; - const size = args.size; - const existing = slots.get(index); - if (existing) slots.set(index, { ...existing, size }); - continue; - } - - if (decoded.eventName === "SetIsShared") { - const args = decoded.args as unknown as { index: bigint; isShared: boolean }; - const index = args.index; - const isShared = args.isShared; - const existing = slots.get(index); - if (existing) slots.set(index, { ...existing, isShared }); - continue; - } - - if (decoded.eventName === "SwapSlots") { - const args = decoded.args as unknown as { index1: bigint; index2: bigint }; - const index1 = args.index1; - const index2 = args.index2; - const parentIndex = getParentIndex(index1); - if (parentIndex !== getParentIndex(index2)) continue; - const siblings = childrenByParent.get(parentIndex); - if (!siblings) continue; - const i1 = siblings.indexOf(index1); - const i2 = siblings.indexOf(index2); - if (i1 === -1 || i2 === -1) continue; - [siblings[i1], siblings[i2]] = [siblings[i2]!, siblings[i1]!]; - continue; - } - - if (decoded.eventName === "AssignNetwork") { - const args = decoded.args as unknown as { index: bigint; subnetwork: Hex }; - const index = args.index; - const subnetwork = args.subnetwork; - const key = subnetwork.toLowerCase(); - subnetworkToSlot.set(key, index); - networkBySlot.set(index, subnetwork); - continue; - } - - if (decoded.eventName === "UnassignNetwork") { - const args = decoded.args as unknown as { subnetwork: Hex }; - const subnetwork = args.subnetwork; - const key = subnetwork.toLowerCase(); - const prevIndex = subnetworkToSlot.get(key); - if (prevIndex !== undefined) networkBySlot.delete(prevIndex); - subnetworkToSlot.delete(key); - continue; - } - - if (decoded.eventName === "AssignOperator") { - const args = decoded.args as unknown as { index: bigint; operator: Address }; - const index = args.index; - const operator = args.operator; - operatorBySlot.set(index, operator); - continue; - } - - if (decoded.eventName === "UnassignOperator") { - const args = decoded.args as unknown as { index: bigint }; - const index = args.index; - operatorBySlot.delete(index); - continue; - } - } - } - - const groupIndices = childrenByParent.get(0n) ?? []; - const applyIsShared = (groupIndex: bigint, slotData: unknown) => { - const slot = slots.get(groupIndex); - if (!slot) return; - const isSharedTrace = - (slotData as { isShared?: unknown })?.isShared ?? (Array.isArray(slotData) ? slotData[2] : undefined); - const isSharedValue = latestTrace208Value(isSharedTrace); - slots.set(groupIndex, { ...slot, isShared: isSharedValue > 0n }); - }; - - if (groupIndices.length > 0) { - const batchSize = 100; - let canUseMulticall = true; - for (let i = 0; i < groupIndices.length; i += batchSize) { - const batch = groupIndices.slice(i, i + batchSize); - if (canUseMulticall) { - try { - const results = await params.publicClient.multicall({ - allowFailure: true, - contracts: batch.map((groupIndex) => ({ - address: params.delegatorAddress, - abi: universalDelegatorAbi, - functionName: "slots", - args: [groupIndex], - })), - }); - results.forEach((result, idx) => { - if (result.status !== "success") return; - const groupIndex = batch[idx]; - if (groupIndex === undefined) return; - applyIsShared(groupIndex, result.result); - }); - continue; - } catch { - canUseMulticall = false; - } - } - - for (const groupIndex of batch) { - const slot = slots.get(groupIndex); - if (!slot) continue; - try { - const slotData = await params.publicClient.readContract({ - abi: universalDelegatorAbi, - address: params.delegatorAddress, - functionName: "slots", - args: [groupIndex], - }); - applyIsShared(groupIndex, slotData); - } catch { - // ignore single-slot failures during reconstruction - } - } - } - } - - const groups: GroupSlot[] = []; - for (const groupIndex of groupIndices) { - const groupSlot = slots.get(groupIndex); - if (!groupSlot) continue; - - const groupDraft: GroupDraft = { size: groupSlot.size.toString(), isShared: groupSlot.isShared }; - const group: GroupSlot = { - id: `group-${formatIndex(groupIndex)}`, - index: groupIndex, - state: { draft: groupDraft, synced: { ...groupDraft } }, - networks: [], - }; - - const networkIndices = childrenByParent.get(groupIndex) ?? []; - for (const networkIndex of networkIndices) { - const networkSlot = slots.get(networkIndex); - if (!networkSlot) continue; - - const subnetwork = networkBySlot.get(networkIndex) ?? ""; - const networkDraft: NetworkDraft = { size: networkSlot.size.toString(), subnetwork }; - const network: NetworkSlot = { - id: `network-${formatIndex(networkIndex)}`, - index: networkIndex, - state: { draft: networkDraft, synced: { ...networkDraft } }, - operators: [], - }; - - const operatorIndices = childrenByParent.get(networkIndex) ?? []; - for (const operatorIndex of operatorIndices) { - const operatorSlot = slots.get(operatorIndex); - if (!operatorSlot) continue; - - const operator = operatorBySlot.get(operatorIndex) ?? ""; - const operatorDraft: OperatorDraft = { size: operatorSlot.size.toString(), operator }; - network.operators.push({ - id: `operator-${formatIndex(operatorIndex)}`, - index: operatorIndex, - state: { draft: operatorDraft, synced: { ...operatorDraft } }, - }); - } - - group.networks.push(network); - } - - groups.push(group); - } - - return { groups }; -} - -function flexGrowFromSize(size: bigint, total: bigint): number { - if (total <= 0n) return 1; - if (size <= 0n) return 0; - const scaled = (size * 1_000_000n) / total; - if (scaled <= 0n) return 0.000001; - return Number(scaled) / 1_000_000; -} - -function percentWidthFromSize(size: bigint, max: bigint, minPct = 40, maxPct = 100): number { - if (max <= 0n) return maxPct; - if (size <= 0n) return minPct; - const scaled = Number((size * 10_000n) / max) / 10_000; - return minPct + scaled * (maxPct - minPct); -} - -function autoSyncAll(model: UniversalDelegatorModel): { model: UniversalDelegatorModel; ops: UdOperation[] } { - const nextModel = cloneModel(model); - const nextOps: UdOperation[] = []; - - for (const group of nextModel.groups) { - // ---------- Group ---------- - { - const draft = group.state.draft; - const size = parseUint(draft.size); - - if (size !== null) { - const synced = group.state.synced; - const syncedSize = synced ? parseUint(synced.size) : null; - const sizeDirty = synced === null || syncedSize === null || syncedSize !== size; - const isDirty = synced === null || synced.isShared !== draft.isShared || sizeDirty; - - if (synced === null || isDirty) { - if (group.index === null) { - const localIndex = BigInt(nextModel.groups.filter((g) => g.index !== null).length + 1); - group.index = createIndex(0n, localIndex); - nextOps.push({ kind: "createSlot", parentIndex: 0n, isShared: draft.isShared, size, slotId: group.id }); - } else { - if (synced && synced.isShared !== draft.isShared) { - nextOps.push({ kind: "setIsShared", index: group.index, isShared: draft.isShared }); - } - if (synced && sizeDirty) { - nextOps.push({ kind: "setSize", index: group.index, size }); - } - } - group.state.synced = { ...draft }; - } - } - } - - // ---------- Networks ---------- - for (const network of group.networks) { - const draft = network.state.draft; - const size = parseUint(draft.size); - if (size === null) continue; - if (group.index === null) continue; - - const subnetworkTrimmed = draft.subnetwork.trim(); - const subnetworkParsed = subnetworkTrimmed === "" ? null : parseBytes32(subnetworkTrimmed); - const subnetworkValid = subnetworkTrimmed === "" || subnetworkParsed !== null; - - const synced = network.state.synced; - const syncedSize = synced ? parseUint(synced.size) : null; - const isSizeDirty = synced === null || syncedSize === null || syncedSize !== size; - const isSubnetworkDirty = - subnetworkValid && (synced === null || synced.subnetwork.trim() !== subnetworkTrimmed); - - if (synced === null || isSizeDirty || isSubnetworkDirty) { - if (network.index === null) { - const localIndex = BigInt(group.networks.filter((n) => n.index !== null).length + 1); - network.index = createIndex(group.index, localIndex); - nextOps.push({ - kind: "createSlot", - parentIndex: group.index, - isShared: false, - size, - slotId: network.id, - }); - if (subnetworkParsed) { - nextOps.push({ kind: "assignNetwork", index: network.index, subnetwork: subnetworkParsed }); - } - } else { - if (synced && isSizeDirty) { - nextOps.push({ kind: "setSize", index: network.index, size }); - } - - if (synced && isSubnetworkDirty) { - const prevTrimmed = synced.subnetwork.trim(); - const nextTrimmed = subnetworkTrimmed; - if (prevTrimmed !== nextTrimmed) { - const prevParsed = prevTrimmed === "" ? null : parseBytes32(prevTrimmed); - if (prevParsed) nextOps.push({ kind: "unassignNetwork", subnetwork: prevParsed }); - if (subnetworkParsed) { - nextOps.push({ kind: "assignNetwork", index: network.index, subnetwork: subnetworkParsed }); - } - } - } - } - - if (synced === null) { - network.state.synced = { - ...draft, - subnetwork: subnetworkValid ? draft.subnetwork : "", - }; - } else { - network.state.synced = { - size: draft.size, - subnetwork: subnetworkValid ? draft.subnetwork : synced.subnetwork, - }; - } - } - - if (network.index === null) continue; - - // ---------- Operators ---------- - for (const operator of network.operators) { - const draftOp = operator.state.draft; - const sizeOp = parseUint(draftOp.size); - if (sizeOp === null) continue; - - const operatorTrimmed = draftOp.operator.trim(); - const operatorValid = operatorTrimmed === "" || isAddress(operatorTrimmed); - - const syncedOp = operator.state.synced; - const syncedSize = syncedOp ? parseUint(syncedOp.size) : null; - const isSizeDirtyOp = syncedOp === null || syncedSize === null || syncedSize !== sizeOp; - const isOperatorDirtyOp = - operatorValid && - (syncedOp === null || syncedOp.operator.trim().toLowerCase() !== operatorTrimmed.toLowerCase()); - - if (syncedOp !== null && !isSizeDirtyOp && !isOperatorDirtyOp) continue; - - if (operator.index === null) { - const localIndex = BigInt(network.operators.filter((o) => o.index !== null).length + 1); - operator.index = createIndex(network.index, localIndex); - nextOps.push({ - kind: "createSlot", - parentIndex: network.index, - isShared: false, - size: sizeOp, - slotId: operator.id, - }); - if (operatorValid && operatorTrimmed) { - nextOps.push({ kind: "assignOperator", index: operator.index, operator: operatorTrimmed as Address }); - } - } else { - if (syncedOp && isSizeDirtyOp) { - nextOps.push({ kind: "setSize", index: operator.index, size: sizeOp }); - } - - if (syncedOp && isOperatorDirtyOp) { - const prevTrimmed = syncedOp.operator.trim(); - const nextTrimmed = operatorTrimmed; - if (prevTrimmed.toLowerCase() !== nextTrimmed.toLowerCase()) { - if (prevTrimmed && isAddress(prevTrimmed)) { - nextOps.push({ - kind: "unassignOperator", - parentIndex: network.index, - operator: prevTrimmed as Address, - }); - } - if (nextTrimmed) { - nextOps.push({ kind: "assignOperator", index: operator.index, operator: nextTrimmed as Address }); - } - } - } - } - - if (syncedOp === null) { - operator.state.synced = { ...draftOp, operator: operatorValid ? draftOp.operator : "" }; - } else { - operator.state.synced = { - size: draftOp.size, - operator: operatorValid ? draftOp.operator : syncedOp.operator, - }; - } - } - } - } - - return { model: nextModel, ops: nextOps }; -} - -type SimSlot = { size: bigint; isShared: boolean }; - -type SimState = { - children: Map; - slots: Map; - created: Set; - networkToSlot: Map; - operatorBySlot: Map; - operatorToSlot: Map; - nextChildLocalIndex: Map; -}; - -function bigintCompare(a: bigint, b: bigint): number { - if (a < b) return -1; - if (a > b) return 1; - return 0; -} - -function shallowOptimizeOps(ops: UdOperation[]): UdOperation[] { - const out: UdOperation[] = []; - for (const op of ops) { - const last = out[out.length - 1]; - if (!last) { - out.push(op); - continue; - } - - if (last.kind === "setSize" && op.kind === "setSize" && last.index === op.index) { - out[out.length - 1] = op; - continue; - } - - if (last.kind === "setIsShared" && op.kind === "setIsShared" && last.index === op.index) { - out[out.length - 1] = op; - continue; - } - - if ( - last.kind === "swapSlots" && - op.kind === "swapSlots" && - last.index1 === op.index2 && - last.index2 === op.index1 - ) { - out.pop(); - continue; - } - - out.push(op); - } - - return out; -} - -function mergeOps(prevOps: UdOperation[], nextOps: UdOperation[]): UdOperation[] { - if (nextOps.length === 0) return prevOps; - const merged = prevOps.slice(); - for (const op of nextOps) { - if (op.kind === "createSlot" && op.slotId) { - const existingIndex = merged.findIndex((item) => item.kind === "createSlot" && item.slotId === op.slotId); - if (existingIndex !== -1) { - merged[existingIndex] = { ...merged[existingIndex], ...op }; - continue; - } - } - merged.push(op); - } - return merged; -} - -function cloneSimState(state: SimState): SimState { - return { - children: new Map([...state.children.entries()].map(([k, v]) => [k, v.slice()])), - slots: new Map([...state.slots.entries()].map(([k, v]) => [k, { ...v }])), - created: new Set(state.created), - networkToSlot: new Map(state.networkToSlot), - operatorBySlot: new Map(state.operatorBySlot), - operatorToSlot: new Map(state.operatorToSlot), - nextChildLocalIndex: new Map(state.nextChildLocalIndex), - }; -} - -function buildSimStateFromModel(model: UniversalDelegatorModel): SimState { - const state: SimState = { - children: new Map([[0n, []]]), - slots: new Map(), - created: new Set([0n]), - networkToSlot: new Map(), - operatorBySlot: new Map(), - operatorToSlot: new Map(), - nextChildLocalIndex: new Map(), - }; - - for (const group of model.groups) { - if (group.index === null) continue; - const groupIndex = group.index; - const groupSynced = group.state.synced; - const groupSize = parseUint(groupSynced?.size ?? group.state.draft.size) ?? 0n; - const groupIsShared = groupSynced?.isShared ?? group.state.draft.isShared; - - state.created.add(groupIndex); - state.slots.set(groupIndex, { size: groupSize, isShared: groupIsShared }); - state.children.get(0n)!.push(groupIndex); - if (!state.children.has(groupIndex)) state.children.set(groupIndex, []); - - for (const network of group.networks) { - if (network.index === null) continue; - const networkIndex = network.index; - const networkSynced = network.state.synced; - const networkSize = parseUint(networkSynced?.size ?? network.state.draft.size) ?? 0n; - - state.created.add(networkIndex); - state.slots.set(networkIndex, { size: networkSize, isShared: false }); - state.children.get(groupIndex)!.push(networkIndex); - if (!state.children.has(networkIndex)) state.children.set(networkIndex, []); - - const subnetworkRaw = (networkSynced?.subnetwork ?? network.state.draft.subnetwork).trim(); - const subnetworkParsed = subnetworkRaw === "" ? null : parseBytes32(subnetworkRaw); - if (subnetworkParsed) { - state.networkToSlot.set(subnetworkParsed.toLowerCase(), networkIndex); - } - - for (const operator of network.operators) { - if (operator.index === null) continue; - const operatorIndex = operator.index; - const operatorSynced = operator.state.synced; - const operatorSize = parseUint(operatorSynced?.size ?? operator.state.draft.size) ?? 0n; - - state.created.add(operatorIndex); - state.slots.set(operatorIndex, { size: operatorSize, isShared: false }); - state.children.get(networkIndex)!.push(operatorIndex); - if (!state.children.has(operatorIndex)) state.children.set(operatorIndex, []); - - const operatorRaw = (operatorSynced?.operator ?? operator.state.draft.operator).trim(); - if (operatorRaw !== "" && isAddress(operatorRaw)) { - const normalized = operatorRaw.toLowerCase(); - state.operatorBySlot.set(operatorIndex, operatorRaw as Address); - state.operatorToSlot.set(`${networkIndex.toString()}:${normalized}`, operatorIndex); - } - } - } - } - - for (const [parentIndex, children] of state.children.entries()) { - let maxChild = 0n; - for (const child of children) maxChild = bigintMax(maxChild, getChildIndex(child)); - state.nextChildLocalIndex.set(parentIndex, maxChild + 1n); - } - - if (!state.nextChildLocalIndex.has(0n)) state.nextChildLocalIndex.set(0n, 1n); - - return state; -} - -function simulateOpsFromState(initial: SimState, ops: UdOperation[]): SimState | null { - const state = cloneSimState(initial); - - for (const op of ops) { - if (op.kind === "createSlot") { - const local = state.nextChildLocalIndex.get(op.parentIndex) ?? 1n; - let index: bigint; - try { - index = createIndex(op.parentIndex, local); - } catch { - return null; - } - - state.nextChildLocalIndex.set(op.parentIndex, local + 1n); - state.created.add(index); - state.slots.set(index, { size: op.size, isShared: op.isShared }); - - if (!state.children.has(op.parentIndex)) state.children.set(op.parentIndex, []); - state.children.get(op.parentIndex)!.push(index); - if (!state.children.has(index)) state.children.set(index, []); - continue; - } - - if (op.kind === "setIsShared") { - const prev = state.slots.get(op.index) ?? { size: 0n, isShared: false }; - state.slots.set(op.index, { ...prev, isShared: op.isShared }); - continue; - } - - if (op.kind === "setSize") { - const prev = state.slots.get(op.index) ?? { size: 0n, isShared: false }; - state.slots.set(op.index, { ...prev, size: op.size }); - continue; - } - - if (op.kind === "swapSlots") { - const parent = getParentIndex(op.index1); - const list = state.children.get(parent); - if (!list) return null; - const i1 = list.indexOf(op.index1); - const i2 = list.indexOf(op.index2); - if (i1 === -1 || i2 === -1) return null; - [list[i1], list[i2]] = [list[i2]!, list[i1]!]; - continue; - } - - if (op.kind === "assignNetwork") { - state.networkToSlot.set(op.subnetwork.toLowerCase(), op.index); - continue; - } - - if (op.kind === "unassignNetwork") { - state.networkToSlot.set(op.subnetwork.toLowerCase(), 0n); - continue; - } - - if (op.kind === "assignOperator") { - const parentIndex = getParentIndex(op.index); - const key = `${parentIndex.toString()}:${op.operator.toLowerCase()}`; - state.operatorToSlot.set(key, op.index); - state.operatorBySlot.set(op.index, op.operator); - continue; - } - - const key = `${op.parentIndex.toString()}:${op.operator.toLowerCase()}`; - const currentIndex = state.operatorToSlot.get(key) ?? 0n; - if (currentIndex !== 0n) state.operatorBySlot.delete(currentIndex); - state.operatorToSlot.set(key, 0n); - } - - return state; -} - -function computeMinimalSwaps(initial: bigint[], target: bigint[]): UdOperation[] | null { - if (initial.length !== target.length) return null; - if (initial.length < 2) return []; - - const current = initial.slice(); - const pos = new Map(); - for (let i = 0; i < current.length; i += 1) pos.set(current[i], i); - - const swaps: UdOperation[] = []; - for (let i = 0; i < target.length; i += 1) { - const desired = target[i]; - const currentAt = current[i]; - if (currentAt === desired) continue; - - const j = pos.get(desired); - if (j === undefined) return null; - if (j < i) return null; - - swaps.push({ kind: "swapSlots", index1: currentAt, index2: desired }); - - current[i] = desired; - current[j] = currentAt; - pos.set(currentAt, j); - pos.set(desired, i); - } - - return swaps; -} - -function compileMinimalOpsFromInitialAndFinal(params: { initial: SimState; final: SimState }): UdOperation[] | null { - const initialExisting = new Set(params.initial.slots.keys()); - const createOps: UdOperation[] = []; - const swapOps: UdOperation[] = []; - const setOps: UdOperation[] = []; - const assignOps: UdOperation[] = []; - - function slotOrDefault(index: bigint): SimSlot { - return params.final.slots.get(index) ?? { size: 0n, isShared: false }; - } - - function buildCreates(parentIndex: bigint, depth: number) { - if (depth >= 3) return; - - const initialChildren = params.initial.children.get(parentIndex) ?? []; - const finalChildren = params.final.children.get(parentIndex) ?? []; - const finalSet = new Set(finalChildren); - - const existingChildrenInOrder = initialChildren.filter((child) => finalSet.has(child)); - const newChildren = finalChildren.filter((child) => !initialExisting.has(child)); - const newChildrenSorted = newChildren.slice().sort((a, b) => bigintCompare(getChildIndex(a), getChildIndex(b))); - - const creationOrder = [...existingChildrenInOrder, ...newChildrenSorted]; - for (const child of creationOrder) { - if (!initialExisting.has(child)) { - const slot = slotOrDefault(child); - createOps.push({ - kind: "createSlot", - parentIndex, - isShared: parentIndex === 0n ? slot.isShared : false, - size: slot.size, - }); - } - buildCreates(child, depth + 1); - } - } - - buildCreates(0n, 0); - - for (const [parentIndex, finalChildren] of params.final.children.entries()) { - const initialChildren = params.initial.children.get(parentIndex) ?? []; - const finalSet = new Set(finalChildren); - - const existingChildrenInOrder = initialChildren.filter((child) => finalSet.has(child)); - const newChildren = finalChildren.filter((child) => !initialExisting.has(child)); - const newChildrenSorted = newChildren.slice().sort((a, b) => bigintCompare(getChildIndex(a), getChildIndex(b))); - - const initialAfterCreate = [...existingChildrenInOrder, ...newChildrenSorted]; - const swaps = computeMinimalSwaps(initialAfterCreate, finalChildren); - if (swaps === null) return null; - swapOps.push(...swaps); - } - - for (const [index, finalSlot] of params.final.slots.entries()) { - if (!initialExisting.has(index)) continue; - const initialSlot = params.initial.slots.get(index) ?? { size: 0n, isShared: false }; - if (initialSlot.size !== finalSlot.size) { - setOps.push({ kind: "setSize", index, size: finalSlot.size }); - } - if (getParentIndex(index) === 0n && initialSlot.isShared !== finalSlot.isShared) { - setOps.push({ kind: "setIsShared", index, isShared: finalSlot.isShared }); - } - } - - const allSubnetworks = new Set(); - for (const key of params.initial.networkToSlot.keys()) allSubnetworks.add(key); - for (const key of params.final.networkToSlot.keys()) allSubnetworks.add(key); - const subnetworkKeys = [...allSubnetworks].sort((a, b) => (a < b ? -1 : a > b ? 1 : 0)); - for (const subnetwork of subnetworkKeys) { - const initialIndex = params.initial.networkToSlot.get(subnetwork) ?? 0n; - const finalIndex = params.final.networkToSlot.get(subnetwork) ?? 0n; - if (initialIndex === finalIndex) continue; - if (initialIndex !== 0n) assignOps.push({ kind: "unassignNetwork", subnetwork: subnetwork as Hex }); - if (finalIndex !== 0n) assignOps.push({ kind: "assignNetwork", index: finalIndex, subnetwork: subnetwork as Hex }); - } - - const allOperators = new Set(); - for (const key of params.initial.operatorToSlot.keys()) allOperators.add(key); - for (const key of params.final.operatorToSlot.keys()) allOperators.add(key); - const operatorKeys = [...allOperators].sort((a, b) => (a < b ? -1 : a > b ? 1 : 0)); - for (const key of operatorKeys) { - const initialIndex = params.initial.operatorToSlot.get(key) ?? 0n; - const finalIndex = params.final.operatorToSlot.get(key) ?? 0n; - if (initialIndex === finalIndex) continue; - - const [parentStr, operator] = key.split(":"); - if (!parentStr || !operator) continue; - let parentIndex: bigint; - try { - parentIndex = BigInt(parentStr); - } catch { - continue; - } - if (initialIndex !== 0n) { - assignOps.push({ kind: "unassignOperator", parentIndex, operator: operator as Address }); - } - if (finalIndex !== 0n) { - assignOps.push({ kind: "assignOperator", index: finalIndex, operator: operator as Address }); - } - } - - return [...createOps, ...swapOps, ...setOps, ...assignOps]; -} - -function compileOpsFromModels(params: { - baselineModel: UniversalDelegatorModel; - nextModel: UniversalDelegatorModel; -}): UdOperation[] | null { - const initial = buildSimStateFromModel(params.baselineModel); - const final = buildSimStateFromModel(params.nextModel); - return compileMinimalOpsFromInitialAndFinal({ initial, final }); -} - -type MulticallCandidate = { label: string; ops: UdOperation[] }; - -function opsKey(ops: UdOperation[]): string { - return JSON.stringify(ops.map(opToJson)); -} - -function buildMulticallCandidates(params: { - ops: UdOperation[]; - baselineModel: UniversalDelegatorModel; -}): MulticallCandidate[] { - const candidates: MulticallCandidate[] = []; - const seen = new Set(); - - function push(label: string, list: UdOperation[]) { - const key = opsKey(list); - if (seen.has(key)) return; - seen.add(key); - candidates.push({ label, ops: list }); - } - - if (params.ops.length === 0) return candidates; - - const initial = buildSimStateFromModel(params.baselineModel); - const final = simulateOpsFromState(initial, params.ops); - if (final) { - const compiled = compileMinimalOpsFromInitialAndFinal({ initial, final }); - if (compiled) { - push("optimized", compiled); - } - } - - push("shallow", shallowOptimizeOps(params.ops)); - push("raw", params.ops); - - return candidates; -} - -function candidatePriority(label: string): number { - if (label === "optimized") return 0; - if (label === "shallow") return 1; - return 2; -} - -function orderMulticallCandidates(candidates: MulticallCandidate[]): MulticallCandidate[] { - return candidates - .slice() - .sort((a, b) => a.ops.length - b.ops.length || candidatePriority(a.label) - candidatePriority(b.label)); -} - -function encodeOpsToCalls(ops: UdOperation[]): Hex[] { - const calls: Hex[] = []; - for (const op of ops) { - if (op.kind === "createSlot") { - calls.push( - encodeFunctionData({ - abi: universalDelegatorAbi, - functionName: "createSlot", - args: [op.parentIndex, op.isShared, op.size], - }), - ); - } else if (op.kind === "setIsShared") { - calls.push( - encodeFunctionData({ - abi: universalDelegatorAbi, - functionName: "setIsShared", - args: [op.index, op.isShared], - }), - ); - } else if (op.kind === "setSize") { - calls.push( - encodeFunctionData({ - abi: universalDelegatorAbi, - functionName: "setSize", - args: [op.index, op.size], - }), - ); - } else if (op.kind === "swapSlots") { - calls.push( - encodeFunctionData({ - abi: universalDelegatorAbi, - functionName: "swapSlots", - args: [op.index1, op.index2], - }), - ); - } else if (op.kind === "assignNetwork") { - calls.push( - encodeFunctionData({ - abi: universalDelegatorAbi, - functionName: "assignNetwork", - args: [op.index, op.subnetwork], - }), - ); - } else if (op.kind === "unassignNetwork") { - calls.push( - encodeFunctionData({ - abi: universalDelegatorAbi, - functionName: "unassignNetwork", - args: [op.subnetwork], - }), - ); - } else if (op.kind === "assignOperator") { - calls.push( - encodeFunctionData({ - abi: universalDelegatorAbi, - functionName: "assignOperator", - args: [op.index, op.operator], - }), - ); - } else { - calls.push( - encodeFunctionData({ - abi: universalDelegatorAbi, - functionName: "unassignOperator", - args: [op.parentIndex, op.operator], - }), - ); - } - } - return calls; -} - -function formatViemError(error: unknown): string { - if (error instanceof ContractFunctionRevertedError) { - const data = error.data; - if (data?.errorName) { - if (data.args && data.args.length > 0) { - const args = data.args.map((arg) => String(arg)).join(", "); - return `${data.errorName}(${args})`; - } - return data.errorName; - } - if (error.reason) return error.reason; - } - if (error instanceof BaseError) return error.shortMessage ?? error.message; - if (error instanceof Error) return error.message; - return "Unknown error"; -} - -function extractRevertName(error: unknown): string | null { - if (error instanceof ContractFunctionRevertedError) return error.data?.errorName ?? null; - if (error instanceof BaseError) { - const nested = error.walk((err) => err instanceof ContractFunctionRevertedError); - if (nested instanceof ContractFunctionRevertedError) return nested.data?.errorName ?? null; - } - return null; -} - -type CandidateSimulationResult = { - candidate: MulticallCandidate; - status: "success" | "failure"; - error?: unknown; -}; - -function computeSimulatedAllocationsFromState(state: SimState, rootBalance: bigint): Map { - const allocated = new Map(); - allocated.set(0n, rootBalance); - - const walk = (parentIndex: bigint) => { - const children = state.children.get(parentIndex) ?? []; - const parentAllocated = allocated.get(parentIndex) ?? 0n; - const parentSlot = state.slots.get(parentIndex); - const parentIsShared = parentIndex === 0n ? false : (parentSlot?.isShared ?? false); - - let prevSum = 0n; - for (const child of children) { - const childSlot = state.slots.get(child) ?? { size: 0n, isShared: false }; - const childAllocated = parentIsShared - ? bigintMin(parentAllocated, childSlot.size) - : bigintMin(saturatingSub(parentAllocated, prevSum), childSlot.size); - allocated.set(child, childAllocated); - prevSum += childSlot.size; - walk(child); - } - }; - - walk(0n); - return allocated; -} - -function describeNotEnoughAvailable(params: { - ops: UdOperation[]; - failureIndex: number; - baselineModel: UniversalDelegatorModel; - rootBalance: bigint | null; -}): string | null { - const failing = params.ops[params.failureIndex]; - if (!failing || failing.kind !== "setSize") return null; - - const initial = buildSimStateFromModel(params.baselineModel); - const before = simulateOpsFromState(initial, params.ops.slice(0, params.failureIndex)); - if (!before) return null; - - const prevSize = before.slots.get(failing.index)?.size ?? 0n; - if (failing.size <= prevSize) return null; - const increase = failing.size - prevSize; - - const parentIndex = getParentIndex(failing.index); - const parentDepth = getDepth(parentIndex); - const childDepth = getDepth(failing.index); - const parentLabel = - parentDepth === 0 - ? "root" - : parentDepth === 1 - ? `Group #${getChildIndex(parentIndex)}` - : `Network #${getChildIndex(parentIndex)}`; - const childLabel = childDepth === 1 ? "Group" : childDepth === 2 ? "Network" : "Operator"; - - const children = before.children.get(parentIndex) ?? []; - let childrenSize = 0n; - for (const child of children) { - childrenSize += before.slots.get(child)?.size ?? 0n; - } - - let available: bigint | null = null; - if (parentIndex === 0n) { - available = params.rootBalance; - } else if (params.rootBalance !== null) { - const allocated = computeSimulatedAllocationsFromState(before, params.rootBalance); - available = allocated.get(parentIndex) ?? null; - } - if (available === null) { - available = before.slots.get(parentIndex)?.size ?? null; - } - if (available === null) return null; - - const unallocated = saturatingSub(available, childrenSize); - if (increase <= unallocated) return null; - return `${childLabel} size increase by ${increase.toString()} in ${parentLabel} exceeds available ${unallocated.toString()}.`; -} - -async function simulateMulticallCandidates(params: { - publicClient: PublicClient; - delegatorAddress: Address; - account: Address; - candidates: MulticallCandidate[]; -}): Promise { - if (params.candidates.length === 0) return []; - const calls = params.candidates.map((candidate) => ({ - to: params.delegatorAddress, - abi: universalDelegatorAbi, - functionName: "multicall", - args: [encodeOpsToCalls(candidate.ops)], - })); - const { results } = await params.publicClient.simulateCalls({ - account: params.account, - calls, - }); - return results.map((result, index) => ({ - candidate: params.candidates[index]!, - status: result.status, - error: result.status === "failure" ? result.error : undefined, - })); -} - -async function simulateMulticall(params: { - publicClient: PublicClient; - delegatorAddress: Address; - account: Address; - calls: Hex[]; -}): Promise { - if (params.calls.length === 0) return; - await params.publicClient.simulateContract({ - address: params.delegatorAddress, - abi: universalDelegatorAbi, - functionName: "multicall", - args: [params.calls], - account: params.account, - }); -} - -async function findFailingOp(params: { - publicClient: PublicClient; - delegatorAddress: Address; - account: Address; - ops: UdOperation[]; -}): Promise<{ index: number; error: unknown } | null> { - if (params.ops.length === 0) return null; - const calls = encodeOpsToCalls(params.ops); - if (calls.length === 0) return null; - - let low = 0; - let high = calls.length - 1; - let failure: { index: number; error: unknown } | null = null; - - while (low <= high) { - const mid = Math.floor((low + high) / 2); - try { - await simulateMulticall({ - publicClient: params.publicClient, - delegatorAddress: params.delegatorAddress, - account: params.account, - calls: calls.slice(0, mid + 1), - }); - low = mid + 1; - } catch (error) { - failure = { index: mid, error }; - high = mid - 1; - } - } - - return failure; +function computeSlotMetrics(params: { + index?: bigint; + size: bigint; + allocationsByIndex: Map; + pendingByIndex: Map; +}): SlotMetrics { + const key = params.index !== undefined ? params.index.toString() : null; + const allocatedRaw = key ? (params.allocationsByIndex.get(key) ?? 0n) : 0n; + const pendingRaw = key ? (params.pendingByIndex.get(key) ?? 0n) : 0n; + const pendingValue = pendingRaw > allocatedRaw ? allocatedRaw : pendingRaw; + const allocatedValue = saturatingSub(allocatedRaw, pendingValue); + const allocatedPct = + params.size > 0n ? Math.min(100, Number((allocatedValue * 10000n) / params.size) / 100) : 0; + const pendingPctRaw = params.size > 0n ? Number((pendingValue * 10000n) / params.size) / 100 : 0; + const pendingPct = Math.max(0, Math.min(100 - allocatedPct, pendingPctRaw)); + + return { allocatedValue, pendingValue, allocatedPct, pendingPct }; } -function opsBaselineModel(params: { - model: UniversalDelegatorModel; - ops: UdOperation[]; - history: Array<{ model: UniversalDelegatorModel; ops: UdOperation[] }>; -}): UniversalDelegatorModel { - if (params.ops.length === 0) return params.model; - for (let i = params.history.length - 1; i >= 0; i -= 1) { - const snapshot = params.history[i]; - if (snapshot && snapshot.ops.length === 0) return snapshot.model; - } - return params.history[0]?.model ?? params.model; +function SlotIndexBadge(props: { index: bigint; onCopy: (index: bigint) => void }) { + return ( + + ); } export function UniversalDelegatorConfigurator() { @@ -1776,7 +246,7 @@ export function UniversalDelegatorConfigurator() { setMulticallErrorOp(null); }; - let candidateResults: CandidateSimulationResult[] | null = null; + let candidateResults: Awaited> | null = null; try { candidateResults = await simulateMulticallCandidates({ publicClient, @@ -2089,9 +559,31 @@ export function UniversalDelegatorConfigurator() { }); }, [encodedCalls]); - function pushHistorySnapshot() { + const pushHistorySnapshot = useCallback(() => { setHistory((prev) => [...prev, { model: cloneModel(model), ops: cloneOps(ops) }]); - } + }, [model, ops]); + + const applyModelUpdate = useCallback( + ( + updater: (current: UniversalDelegatorModel) => UniversalDelegatorModel, + options?: { syncOps?: boolean }, + ) => { + pushHistorySnapshot(); + setModel((prev) => { + const updated = updater(prev); + if (options?.syncOps === false) return updated; + const auto = autoSyncAll(updated); + setOps((prevOps) => { + const compiled = compileOpsFromModels({ baselineModel, nextModel: auto.model }); + if (compiled) return compiled; + if (auto.ops.length === 0) return prevOps; + return shallowOptimizeOps(mergeOps(prevOps, auto.ops)); + }); + return auto.model; + }); + }, + [baselineModel, pushHistorySnapshot], + ); const undo = useCallback(() => { setHistory((prev) => { @@ -2175,19 +667,17 @@ export function UniversalDelegatorConfigurator() { }, [delegatorAddress, publicClient, reconstructNonce]); function addDraftGroup() { - pushHistorySnapshot(); const group: GroupSlot = { id: newId("group"), index: null, state: { draft: { size: "", isShared: false }, synced: null }, networks: [], }; - setModel((prev) => ({ ...prev, groups: [...prev.groups, group] })); + applyModelUpdate((prev) => ({ ...prev, groups: [...prev.groups, group] }), { syncOps: false }); } function addGroupFromTemplate() { if (!addGroupValid) return; - pushHistorySnapshot(); const makeOperator = (): OperatorSlot => ({ id: newId("operator"), index: null, @@ -2222,7 +712,7 @@ export function UniversalDelegatorConfigurator() { state: { draft: { size: "", isShared }, synced: null }, networks, }; - setModel((prev) => ({ ...prev, groups: [...prev.groups, group] })); + applyModelUpdate((prev) => ({ ...prev, groups: [...prev.groups, group] }), { syncOps: false }); } function swapNeighborSlots() { @@ -2284,30 +774,15 @@ export function UniversalDelegatorConfigurator() { } function updateGroupDraft(groupId: string, patch: Partial) { - pushHistorySnapshot(); - setModel((prev) => { - const updated: UniversalDelegatorModel = { - ...prev, - groups: prev.groups.map((g) => - g.id === groupId ? { ...g, state: { ...g.state, draft: { ...g.state.draft, ...patch } } } : g, - ), - }; - const auto = autoSyncAll(updated); - setOps((prevOps) => { - const compiled = compileOpsFromModels({ baselineModel, nextModel: auto.model }); - if (compiled) return compiled; - if (auto.ops.length === 0) return prevOps; - return shallowOptimizeOps(mergeOps(prevOps, auto.ops)); - }); - return auto.model; - }); + applyModelUpdate((prev) => ({ + ...prev, + groups: prev.groups.map((g) => + g.id === groupId ? { ...g, state: { ...g.state, draft: { ...g.state.draft, ...patch } } } : g, + ), + })); } function addDraftNetwork(groupId: string) { - pushHistorySnapshot(); - const group = model.groups.find((g) => g.id === groupId); - if (!group) return; - const network: NetworkSlot = { id: newId("network"), index: null, @@ -2315,36 +790,28 @@ export function UniversalDelegatorConfigurator() { operators: [], }; - setModel((prev) => ({ - ...prev, - groups: prev.groups.map((g) => (g.id === groupId ? { ...g, networks: [...g.networks, network] } : g)), - })); + applyModelUpdate( + (prev) => ({ + ...prev, + groups: prev.groups.map((g) => (g.id === groupId ? { ...g, networks: [...g.networks, network] } : g)), + }), + { syncOps: false }, + ); } function updateNetworkDraft(groupId: string, networkId: string, patch: Partial) { - pushHistorySnapshot(); - setModel((prev) => { - const updated: UniversalDelegatorModel = { - ...prev, - groups: prev.groups.map((g) => { - if (g.id !== groupId) return g; - return { - ...g, - networks: g.networks.map((n) => - n.id === networkId ? { ...n, state: { ...n.state, draft: { ...n.state.draft, ...patch } } } : n, - ), - }; - }), - }; - const auto = autoSyncAll(updated); - setOps((prevOps) => { - const compiled = compileOpsFromModels({ baselineModel, nextModel: auto.model }); - if (compiled) return compiled; - if (auto.ops.length === 0) return prevOps; - return shallowOptimizeOps(mergeOps(prevOps, auto.ops)); - }); - return auto.model; - }); + applyModelUpdate((prev) => ({ + ...prev, + groups: prev.groups.map((g) => { + if (g.id !== groupId) return g; + return { + ...g, + networks: g.networks.map((n) => + n.id === networkId ? { ...n, state: { ...n.state, draft: { ...n.state.draft, ...patch } } } : n, + ), + }; + }), + })); } function addDraftOperator(groupId: string, networkId: string) { @@ -2352,58 +819,48 @@ export function UniversalDelegatorConfigurator() { const network = group?.networks.find((n) => n.id === networkId); if (!network) return; - pushHistorySnapshot(); - const slot: OperatorSlot = { id: newId("operator"), index: null, state: { draft: { size: "", operator: "" }, synced: null }, }; - setModel((prev) => ({ + applyModelUpdate( + (prev) => ({ + ...prev, + groups: prev.groups.map((g) => { + if (g.id !== groupId) return g; + return { + ...g, + networks: g.networks.map((n) => (n.id === networkId ? { ...n, operators: [...n.operators, slot] } : n)), + }; + }), + }), + { syncOps: false }, + ); + } + + function updateOperatorDraft(groupId: string, networkId: string, operatorId: string, patch: Partial) { + applyModelUpdate((prev) => ({ ...prev, groups: prev.groups.map((g) => { if (g.id !== groupId) return g; return { ...g, - networks: g.networks.map((n) => (n.id === networkId ? { ...n, operators: [...n.operators, slot] } : n)), + networks: g.networks.map((n) => { + if (n.id !== networkId) return n; + return { + ...n, + operators: n.operators.map((o) => + o.id === operatorId ? { ...o, state: { ...o.state, draft: { ...o.state.draft, ...patch } } } : o, + ), + }; + }), }; }), })); } - function updateOperatorDraft(groupId: string, networkId: string, operatorId: string, patch: Partial) { - pushHistorySnapshot(); - setModel((prev) => { - const updated: UniversalDelegatorModel = { - ...prev, - groups: prev.groups.map((g) => { - if (g.id !== groupId) return g; - return { - ...g, - networks: g.networks.map((n) => { - if (n.id !== networkId) return n; - return { - ...n, - operators: n.operators.map((o) => - o.id === operatorId ? { ...o, state: { ...o.state, draft: { ...o.state.draft, ...patch } } } : o, - ), - }; - }), - }; - }), - }; - const auto = autoSyncAll(updated); - setOps((prevOps) => { - const compiled = compileOpsFromModels({ baselineModel, nextModel: auto.model }); - if (compiled) return compiled; - if (auto.ops.length === 0) return prevOps; - return shallowOptimizeOps(mergeOps(prevOps, auto.ops)); - }); - return auto.model; - }); - } - async function executeMulticall() { if (!isConnected || !accountAddress) return; if (!isAddress(delegatorAddress)) return; @@ -2830,7 +1287,17 @@ export function UniversalDelegatorConfigurator() {
- Allocated: {canReadBalances ? (rootBalance?.toString() ?? (balancesLoading ? "loading…" : "—")) : "—"} +
+ Allocated: {canReadBalances ? (rootBalance?.toString() ?? (balancesLoading ? "loading…" : "—")) : "—"} +
+
+ Pending:{" "} + {!canReadBalances || !hasRootBalance + ? "—" + : pendingLoading + ? "loading…" + : (pendingByIndex.get("0") ?? 0n).toString()} +
@@ -2843,17 +1310,13 @@ export function UniversalDelegatorConfigurator() { const widthSizeValue = groupSizeValues[groupPos] ?? 0n; const groupGrow = flexGrowFromSize(widthSizeValue, groupTotalSize); const fillSizeValue = effectiveSize(group.state); - const allocatedRaw = - groupIndex !== undefined ? (allocationsByIndex.get(groupIndex.toString()) ?? 0n) : 0n; - const pendingRaw = - groupIndex !== undefined ? (pendingByIndex.get(groupIndex.toString()) ?? 0n) : 0n; - const pendingValue = pendingRaw > allocatedRaw ? allocatedRaw : pendingRaw; - const allocatedValue = saturatingSub(allocatedRaw, pendingValue); - const allocatedPct = - fillSizeValue > 0n ? Math.min(100, Number((allocatedValue * 10000n) / fillSizeValue) / 100) : 0; - const pendingPctRaw = - fillSizeValue > 0n ? Number((pendingValue * 10000n) / fillSizeValue) / 100 : 0; - const pendingPct = Math.max(0, Math.min(100 - allocatedPct, pendingPctRaw)); + const metrics = computeSlotMetrics({ + index: groupIndex, + size: fillSizeValue, + allocationsByIndex, + pendingByIndex, + }); + const { allocatedValue, pendingValue, allocatedPct, pendingPct } = metrics; const isGroupFocused = zoom.kind !== "all" && zoom.groupId === group.id; const isGroupHovered = hoveredGroupId === group.id; const handleGroupClick = (event: MouseEvent) => { @@ -2907,14 +1370,7 @@ export function UniversalDelegatorConfigurator() {
{groupIndex !== undefined ? ( - + ) : null}
Group
@@ -3019,69 +1475,6 @@ export function UniversalDelegatorConfigurator() { ); } -function formatOp(op: UdOperation): string { - if (op.kind === "createSlot") { - return `createSlot(${formatIndex(op.parentIndex)}, ${op.isShared}, ${op.size})`; - } - if (op.kind === "setIsShared") { - return `setIsShared(${formatIndex(op.index)}, ${op.isShared})`; - } - if (op.kind === "setSize") { - return `setSize(${formatIndex(op.index)}, ${op.size})`; - } - if (op.kind === "swapSlots") { - return `swapSlots(${formatIndex(op.index1)}, ${formatIndex(op.index2)})`; - } - if (op.kind === "assignNetwork") { - return `assignNetwork(${formatIndex(op.index)}, ${op.subnetwork})`; - } - if (op.kind === "unassignNetwork") { - return `unassignNetwork(${op.subnetwork})`; - } - if (op.kind === "assignOperator") { - return `assignOperator(${formatIndex(op.index)}, ${op.operator})`; - } - return `unassignOperator(${formatIndex(op.parentIndex)}, ${op.operator})`; -} - -function opToJson(op: UdOperation): Record { - if (op.kind === "createSlot") { - return { - kind: op.kind, - parentIndex: formatIndex(op.parentIndex), - isShared: op.isShared, - size: op.size.toString(), - }; - } - if (op.kind === "setIsShared") { - return { kind: op.kind, index: formatIndex(op.index), isShared: op.isShared }; - } - if (op.kind === "setSize") { - return { kind: op.kind, index: formatIndex(op.index), size: op.size.toString() }; - } - if (op.kind === "swapSlots") { - return { - kind: op.kind, - index1: formatIndex(op.index1), - index2: formatIndex(op.index2), - }; - } - if (op.kind === "assignNetwork") { - return { kind: op.kind, index: formatIndex(op.index), subnetwork: op.subnetwork }; - } - if (op.kind === "unassignNetwork") { - return { kind: op.kind, subnetwork: op.subnetwork }; - } - if (op.kind === "assignOperator") { - return { kind: op.kind, index: formatIndex(op.index), operator: op.operator }; - } - return { - kind: op.kind, - parentIndex: formatIndex(op.parentIndex), - operator: op.operator, - }; -} - function NetworksRow(props: { group: GroupSlot; slotIdToIndex: Map; @@ -3134,16 +1527,13 @@ function NetworksRow(props: { const networkGrow = flexGrowFromSize(widthSizeValue, networksTotalSize); const networkWidthPct = percentWidthFromSize(widthSizeValue, networksMaxSize, 60, 100); const fillSizeValue = effectiveSize(network.state); - const allocatedRaw = - networkIndex !== undefined ? (props.allocatedByIndex.get(networkIndex.toString()) ?? 0n) : 0n; - const pendingRaw = - networkIndex !== undefined ? (props.pendingByIndex.get(networkIndex.toString()) ?? 0n) : 0n; - const pendingValue = pendingRaw > allocatedRaw ? allocatedRaw : pendingRaw; - const allocatedValue = saturatingSub(allocatedRaw, pendingValue); - const allocatedPct = - fillSizeValue > 0n ? Math.min(100, Number((allocatedValue * 10000n) / fillSizeValue) / 100) : 0; - const pendingPctRaw = fillSizeValue > 0n ? Number((pendingValue * 10000n) / fillSizeValue) / 100 : 0; - const pendingPct = Math.max(0, Math.min(100 - allocatedPct, pendingPctRaw)); + const metrics = computeSlotMetrics({ + index: networkIndex, + size: fillSizeValue, + allocationsByIndex: props.allocatedByIndex, + pendingByIndex: props.pendingByIndex, + }); + const { allocatedValue, pendingValue, allocatedPct, pendingPct } = metrics; const subnetworkTrimmed = draft.subnetwork.trim(); const subnetworkValid = subnetworkTrimmed === "" || parseBytes32(subnetworkTrimmed) !== null; const isFocused = focusedNetworkId === network.id; @@ -3203,14 +1593,7 @@ function NetworksRow(props: {
{networkIndex !== undefined ? ( - + ) : null}
Network
@@ -3339,16 +1722,13 @@ function OperatorsRow(props: { const widthSizeValue = operatorSizeValues[operatorPos] ?? 0n; const operatorGrow = flexGrowFromSize(widthSizeValue, operatorsTotalSize); const fillSizeValue = effectiveSize(operator.state); - const allocatedRaw = - operatorIndex !== undefined ? (props.allocatedByIndex.get(operatorIndex.toString()) ?? 0n) : 0n; - const pendingRaw = - operatorIndex !== undefined ? (props.pendingByIndex.get(operatorIndex.toString()) ?? 0n) : 0n; - const pendingValue = pendingRaw > allocatedRaw ? allocatedRaw : pendingRaw; - const allocatedValue = saturatingSub(allocatedRaw, pendingValue); - const allocatedPct = - fillSizeValue > 0n ? Math.min(100, Number((allocatedValue * 10000n) / fillSizeValue) / 100) : 0; - const pendingPctRaw = fillSizeValue > 0n ? Number((pendingValue * 10000n) / fillSizeValue) / 100 : 0; - const pendingPct = Math.max(0, Math.min(100 - allocatedPct, pendingPctRaw)); + const metrics = computeSlotMetrics({ + index: operatorIndex, + size: fillSizeValue, + allocationsByIndex: props.allocatedByIndex, + pendingByIndex: props.pendingByIndex, + }); + const { allocatedValue, pendingValue, allocatedPct, pendingPct } = metrics; const operatorTrimmed = draft.operator.trim(); const operatorValid = operatorTrimmed === "" || isAddress(operatorTrimmed); return ( @@ -3377,14 +1757,7 @@ function OperatorsRow(props: {
{operatorIndex !== undefined ? ( - + ) : null}
Operator
diff --git a/ui/src/pages/universalDelegator/logic.ts b/ui/src/pages/universalDelegator/logic.ts new file mode 100644 index 00000000..d71b754a --- /dev/null +++ b/ui/src/pages/universalDelegator/logic.ts @@ -0,0 +1,1682 @@ +import { + type Address, + BaseError, + ContractFunctionRevertedError, + type Hex, + type PublicClient, + decodeEventLog, + encodeFunctionData, + getEventSelector, + isAddress, + isHex, + padHex, +} from "viem"; + +import { universalDelegatorAbi } from "../../contracts/universalDelegator"; +import { createIndex, formatIndex, getChildIndex, getDepth, getParentIndex } from "../../utils/universalDelegatorIndex"; + +const UNIVERSAL_DELEGATOR_EVENT_ABI = universalDelegatorAbi.filter((item) => item.type === "event") as unknown as Array< + (typeof universalDelegatorAbi)[number] +>; + +const UNIVERSAL_DELEGATOR_EVENT_TOPICS = new Set( + UNIVERSAL_DELEGATOR_EVENT_ABI.map((event) => getEventSelector(event as never)), +); + +export type SlotSizeInput = string; + +export type DraftState = { + draft: T; + synced: T | null; +}; + +export type GroupDraft = { size: SlotSizeInput; isShared: boolean }; +export type NetworkDraft = { size: SlotSizeInput; subnetwork: string }; +export type OperatorDraft = { size: SlotSizeInput; operator: string }; + +export type OperatorSlot = { + id: string; + index: bigint | null; + state: DraftState; +}; + +export type NetworkSlot = { + id: string; + index: bigint | null; + state: DraftState; + operators: OperatorSlot[]; +}; + +export type GroupSlot = { + id: string; + index: bigint | null; + state: DraftState; + networks: NetworkSlot[]; +}; + +export type UniversalDelegatorModel = { + groups: GroupSlot[]; +}; + +export type ZoomState = + | { kind: "all" } + | { kind: "group"; groupId: string } + | { kind: "network"; groupId: string; networkId: string }; + +export type GroupConstructor = "shared-multi" | "shared-single" | "single-multi" | "single-single"; + +export type UdOperation = + | { kind: "createSlot"; parentIndex: bigint; isShared: boolean; size: bigint; slotId?: string } + | { kind: "setIsShared"; index: bigint; isShared: boolean } + | { kind: "setSize"; index: bigint; size: bigint } + | { kind: "swapSlots"; index1: bigint; index2: bigint } + | { kind: "assignNetwork"; index: bigint; subnetwork: Hex } + | { kind: "unassignNetwork"; subnetwork: Hex } + | { kind: "assignOperator"; index: bigint; operator: Address } + | { kind: "unassignOperator"; parentIndex: bigint; operator: Address }; + +export function parseUint(value: string): bigint | null { + const normalized = value.trim(); + if (!normalized) return 0n; + try { + const parsed = BigInt(normalized); + if (parsed < 0n) return null; + return parsed; + } catch { + return null; + } +} + +export function parseBytes32(value: string): Hex | null { + const trimmed = value.trim(); + if (!trimmed) return null; + if (!trimmed.startsWith("0x")) return null; + if (!isHex(trimmed)) return null; + if (trimmed.length > 66) return null; + return padHex(trimmed, { size: 32, dir: "right" }); +} + +export type HasSize = { size: SlotSizeInput }; + +export function effectiveSize(state: DraftState): bigint { + const draft = parseUint(state.draft.size); + if (draft !== null) return draft; + const synced = state.synced ? parseUint(state.synced.size) : null; + return synced ?? 0n; +} + +export function sumBigints(values: bigint[]): bigint { + let total = 0n; + for (const v of values) total += v; + return total; +} + +export function maxBigint(values: bigint[]): bigint { + let m = 0n; + for (const v of values) if (v > m) m = v; + return m; +} + +export function formatShortAddress(address: string): string { + if (address.length <= 10) return address; + return `${address.slice(0, 6)}...${address.slice(-4)}`; +} + +export function parsePositiveInt(value: string): number | null { + const trimmed = value.trim(); + if (!trimmed) return null; + const parsed = Number(trimmed); + if (!Number.isFinite(parsed) || !Number.isInteger(parsed) || parsed <= 0) return null; + return parsed; +} + +export function cloneOps(values: UdOperation[]): UdOperation[] { + return values.map((op) => ({ ...op })); +} + +export function cloneModel(values: UniversalDelegatorModel): UniversalDelegatorModel { + return { + groups: values.groups.map((group) => ({ + id: group.id, + index: group.index, + state: { + draft: { ...group.state.draft }, + synced: group.state.synced ? { ...group.state.synced } : null, + }, + networks: group.networks.map((network) => ({ + id: network.id, + index: network.index, + state: { + draft: { ...network.state.draft }, + synced: network.state.synced ? { ...network.state.synced } : null, + }, + operators: network.operators.map((operator) => ({ + id: operator.id, + index: operator.index, + state: { + draft: { ...operator.state.draft }, + synced: operator.state.synced ? { ...operator.state.synced } : null, + }, + })), + })), + })), + }; +} + +type OnchainSlotSnapshot = { size: bigint; isShared: boolean }; + +function latestTrace208Value(trace: unknown): bigint { + const checkpoints = (trace as { _trace?: { _checkpoints?: Array<{ _value: bigint }> } })?._trace?._checkpoints; + if (!checkpoints || checkpoints.length === 0) return 0n; + return checkpoints[checkpoints.length - 1]?._value ?? 0n; +} + +function ensureChildren(map: Map, parentIndex: bigint): bigint[] { + const existing = map.get(parentIndex); + if (existing) return existing; + const created: bigint[] = []; + map.set(parentIndex, created); + return created; +} + +export function bigintMin(a: bigint, b: bigint): bigint { + return a < b ? a : b; +} + +export function bigintMax(a: bigint, b: bigint): bigint { + return a > b ? a : b; +} + +export function saturatingSub(a: bigint, b: bigint): bigint { + return a > b ? a - b : 0n; +} + +export function computeSlotIdToIndex(model: UniversalDelegatorModel): Map { + const idToIndex = new Map(); + + let maxGroupChild = 0n; + for (const group of model.groups) { + if (group.index === null) continue; + maxGroupChild = bigintMax(maxGroupChild, getChildIndex(group.index)); + } + let nextGroupChild = maxGroupChild + 1n; + + for (const group of model.groups) { + const groupIndex = group.index ?? createIndex(0n, nextGroupChild++); + idToIndex.set(group.id, groupIndex); + + let maxNetworkChild = 0n; + for (const network of group.networks) { + if (network.index === null) continue; + maxNetworkChild = bigintMax(maxNetworkChild, getChildIndex(network.index)); + } + let nextNetworkChild = maxNetworkChild + 1n; + + for (const network of group.networks) { + const networkIndex = network.index ?? createIndex(groupIndex, nextNetworkChild++); + idToIndex.set(network.id, networkIndex); + + let maxOperatorChild = 0n; + for (const operator of network.operators) { + if (operator.index === null) continue; + maxOperatorChild = bigintMax(maxOperatorChild, getChildIndex(operator.index)); + } + let nextOperatorChild = maxOperatorChild + 1n; + + for (const operator of network.operators) { + const operatorIndex = operator.index ?? createIndex(networkIndex, nextOperatorChild++); + idToIndex.set(operator.id, operatorIndex); + } + } + } + + return idToIndex; +} + +export function computeSimulatedAllocations( + model: UniversalDelegatorModel, + slotIdToIndex: Map, + rootActiveStake: bigint | null, +): Map { + const allocatedByIndex = new Map(); + const rootBalance = rootActiveStake ?? 0n; + allocatedByIndex.set("0", rootBalance); + + let groupPrevSum = 0n; + for (const group of model.groups) { + const groupSize = effectiveSize(group.state); + const groupAllocated = bigintMin(saturatingSub(rootBalance, groupPrevSum), groupSize); + const groupIndex = slotIdToIndex.get(group.id); + if (groupIndex !== undefined) allocatedByIndex.set(groupIndex.toString(), groupAllocated); + groupPrevSum += groupSize; + + const groupIsShared = group.state.draft.isShared; + let networkPrevSum = 0n; + for (const network of group.networks) { + const networkSize = effectiveSize(network.state); + const networkAllocated = groupIsShared + ? bigintMin(groupAllocated, networkSize) + : bigintMin(saturatingSub(groupAllocated, networkPrevSum), networkSize); + const networkIndex = slotIdToIndex.get(network.id); + if (networkIndex !== undefined) allocatedByIndex.set(networkIndex.toString(), networkAllocated); + networkPrevSum += networkSize; + + let operatorPrevSum = 0n; + for (const operator of network.operators) { + const operatorSize = effectiveSize(operator.state); + const operatorAllocated = bigintMin(saturatingSub(networkAllocated, operatorPrevSum), operatorSize); + const operatorIndex = slotIdToIndex.get(operator.id); + if (operatorIndex !== undefined) allocatedByIndex.set(operatorIndex.toString(), operatorAllocated); + operatorPrevSum += operatorSize; + } + } + } + + return allocatedByIndex; +} + +function computePendingByIndex(params: { + model: UniversalDelegatorModel; + slotIdToIndex: Map; + baselineSlotIdToIndex: Map; + baselineAllocationsByIndex: Map; +}): Map { + const pendingByIndex = new Map(); + const baselineAllocations = params.baselineAllocationsByIndex; + const baselineIndices = params.baselineSlotIdToIndex; + + const baselineAllocatedFor = (slotId: string): bigint => { + const baselineIndex = baselineIndices.get(slotId); + if (baselineIndex === undefined) return 0n; + return baselineAllocations.get(baselineIndex.toString()) ?? 0n; + }; + + let rootPending = 0n; + for (const group of params.model.groups) { + let groupPending = 0n; + for (const network of group.networks) { + let networkPending = 0n; + for (const operator of network.operators) { + const operatorIndex = params.slotIdToIndex.get(operator.id); + if (operatorIndex !== undefined) pendingByIndex.set(operatorIndex.toString(), 0n); + + const baselineAllocated = baselineAllocatedFor(operator.id); + const nextSize = effectiveSize(operator.state); + if (baselineAllocated > nextSize) { + networkPending += baselineAllocated - nextSize; + } + } + + const networkIndex = params.slotIdToIndex.get(network.id); + if (networkIndex !== undefined) pendingByIndex.set(networkIndex.toString(), networkPending); + + const baselineAllocated = baselineAllocatedFor(network.id); + const nextSize = effectiveSize(network.state); + if (baselineAllocated > nextSize) { + groupPending += baselineAllocated - nextSize; + } + } + + const groupIndex = params.slotIdToIndex.get(group.id); + if (groupIndex !== undefined) pendingByIndex.set(groupIndex.toString(), groupPending); + + const baselineAllocated = baselineAllocatedFor(group.id); + const nextSize = effectiveSize(group.state); + if (baselineAllocated > nextSize) { + rootPending += baselineAllocated - nextSize; + } + } + + pendingByIndex.set("0", rootPending); + return pendingByIndex; +} + +function computeSimulatedAllocationsFromStateWithPending( + state: SimState, + rootBalance: bigint, + pendingByIndex: Map, +): Map { + const allocated = new Map(); + allocated.set(0n, rootBalance); + + const walk = (parentIndex: bigint) => { + const children = state.children.get(parentIndex) ?? []; + const parentAllocated = allocated.get(parentIndex) ?? 0n; + const parentPending = pendingByIndex.get(parentIndex) ?? 0n; + const parentAvailable = saturatingSub(parentAllocated, parentPending); + const parentSlot = state.slots.get(parentIndex); + const parentIsShared = parentIndex === 0n ? false : (parentSlot?.isShared ?? false); + + let prevSum = 0n; + for (const child of children) { + const childSlot = state.slots.get(child) ?? { size: 0n, isShared: false }; + const childAllocated = parentIsShared + ? bigintMin(parentAvailable, childSlot.size) + : bigintMin(saturatingSub(parentAvailable, prevSum), childSlot.size); + allocated.set(child, childAllocated); + prevSum += childSlot.size; + walk(child); + } + }; + + walk(0n); + return allocated; +} + +export function computePendingByIndexFromOps(params: { + baselineModel: UniversalDelegatorModel; + ops: UdOperation[]; + rootActiveStake: bigint | null; + baselinePendingByIndex?: Map | null; +}): Map { + if (params.ops.length === 0) return new Map(); + + const state = buildSimStateFromModel(params.baselineModel); + const pendingByIndex = new Map(); + if (params.baselinePendingByIndex) { + for (const [key, value] of params.baselinePendingByIndex.entries()) { + if (value <= 0n) continue; + try { + pendingByIndex.set(BigInt(key), value); + } catch { + // ignore invalid pending keys + } + } + } + const rootBalance = params.rootActiveStake ?? 0n; + + const addPending = (index: bigint, delta: bigint) => { + if (delta <= 0n) return; + pendingByIndex.set(index, (pendingByIndex.get(index) ?? 0n) + delta); + }; + + for (const op of params.ops) { + if (op.kind === "createSlot") { + const local = state.nextChildLocalIndex.get(op.parentIndex) ?? 1n; + let index: bigint; + try { + index = createIndex(op.parentIndex, local); + } catch { + return new Map(); + } + + state.nextChildLocalIndex.set(op.parentIndex, local + 1n); + state.created.add(index); + state.slots.set(index, { size: op.size, isShared: op.isShared }); + + if (!state.children.has(op.parentIndex)) state.children.set(op.parentIndex, []); + state.children.get(op.parentIndex)!.push(index); + if (!state.children.has(index)) state.children.set(index, []); + continue; + } + + if (op.kind === "setIsShared") { + const prev = state.slots.get(op.index) ?? { size: 0n, isShared: false }; + state.slots.set(op.index, { ...prev, isShared: op.isShared }); + continue; + } + + if (op.kind === "setSize") { + const prev = state.slots.get(op.index) ?? { size: 0n, isShared: false }; + if (op.size < prev.size) { + const allocated = computeSimulatedAllocationsFromStateWithPending(state, rootBalance, pendingByIndex); + const allocatedNow = allocated.get(op.index) ?? 0n; + if (allocatedNow > op.size) { + addPending(getParentIndex(op.index), allocatedNow - op.size); + } + } + state.slots.set(op.index, { ...prev, size: op.size }); + continue; + } + + if (op.kind === "swapSlots") { + const parent = getParentIndex(op.index1); + const list = state.children.get(parent); + if (!list) return new Map(); + const i1 = list.indexOf(op.index1); + const i2 = list.indexOf(op.index2); + if (i1 === -1 || i2 === -1) return new Map(); + [list[i1], list[i2]] = [list[i2]!, list[i1]!]; + continue; + } + + if (op.kind === "assignNetwork") { + state.networkToSlot.set(op.subnetwork.toLowerCase(), op.index); + continue; + } + + if (op.kind === "unassignNetwork") { + state.networkToSlot.set(op.subnetwork.toLowerCase(), 0n); + continue; + } + + if (op.kind === "assignOperator") { + const parentIndex = getParentIndex(op.index); + const key = `${parentIndex.toString()}:${op.operator.toLowerCase()}`; + state.operatorToSlot.set(key, op.index); + state.operatorBySlot.set(op.index, op.operator); + continue; + } + + const key = `${op.parentIndex.toString()}:${op.operator.toLowerCase()}`; + const currentIndex = state.operatorToSlot.get(key) ?? 0n; + if (currentIndex !== 0n) state.operatorBySlot.delete(currentIndex); + state.operatorToSlot.set(key, 0n); + } + + const result = new Map(); + for (const [index, value] of pendingByIndex.entries()) { + result.set(index.toString(), value); + } + return result; +} + +export function computeSimulatedAllocationsWithPending(params: { + model: UniversalDelegatorModel; + slotIdToIndex: Map; + baselineSlotIdToIndex: Map; + baselineAllocationsByIndex: Map; + rootActiveStake: bigint | null; + pendingByIndexOverride?: Map | null; +}): { allocatedByIndex: Map; pendingByIndex: Map } { + const allocatedByIndex = new Map(); + const rootBalance = params.rootActiveStake ?? 0n; + const pendingByIndex = + params.pendingByIndexOverride ?? + computePendingByIndex({ + model: params.model, + slotIdToIndex: params.slotIdToIndex, + baselineSlotIdToIndex: params.baselineSlotIdToIndex, + baselineAllocationsByIndex: params.baselineAllocationsByIndex, + }); + const rootPending = pendingByIndex.get("0") ?? 0n; + const rootAvailable = saturatingSub(rootBalance, rootPending); + + allocatedByIndex.set("0", rootBalance); + + let groupPrevSum = 0n; + for (const group of params.model.groups) { + const groupSize = effectiveSize(group.state); + const groupAllocated = bigintMin(saturatingSub(rootAvailable, groupPrevSum), groupSize); + const groupIndex = params.slotIdToIndex.get(group.id); + if (groupIndex !== undefined) allocatedByIndex.set(groupIndex.toString(), groupAllocated); + groupPrevSum += groupSize; + + const groupIsShared = group.state.draft.isShared; + const groupPending = groupIndex !== undefined ? (pendingByIndex.get(groupIndex.toString()) ?? 0n) : 0n; + const groupAvailable = saturatingSub(groupAllocated, groupPending); + let networkPrevSum = 0n; + for (const network of group.networks) { + const networkSize = effectiveSize(network.state); + const networkAllocated = groupIsShared + ? bigintMin(groupAvailable, networkSize) + : bigintMin(saturatingSub(groupAvailable, networkPrevSum), networkSize); + const networkIndex = params.slotIdToIndex.get(network.id); + if (networkIndex !== undefined) allocatedByIndex.set(networkIndex.toString(), networkAllocated); + networkPrevSum += networkSize; + + const networkPending = networkIndex !== undefined ? (pendingByIndex.get(networkIndex.toString()) ?? 0n) : 0n; + const networkAvailable = saturatingSub(networkAllocated, networkPending); + let operatorPrevSum = 0n; + for (const operator of network.operators) { + const operatorSize = effectiveSize(operator.state); + const operatorAllocated = bigintMin(saturatingSub(networkAvailable, operatorPrevSum), operatorSize); + const operatorIndex = params.slotIdToIndex.get(operator.id); + if (operatorIndex !== undefined) allocatedByIndex.set(operatorIndex.toString(), operatorAllocated); + operatorPrevSum += operatorSize; + } + } + } + + return { allocatedByIndex, pendingByIndex }; +} + +export async function reconstructModelFromChain(params: { + delegatorAddress: Address; + publicClient: PublicClient; +}): Promise { + const latestBlock = await params.publicClient.getBlockNumber(); + + const slots = new Map(); + const childrenByParent = new Map(); + const networkBySlot = new Map(); + const subnetworkToSlot = new Map(); + const operatorBySlot = new Map(); + + const chunkSize = 50_000n; + for (let fromBlock = 0n; fromBlock <= latestBlock; fromBlock += chunkSize) { + const toBlock = (() => { + const candidate = fromBlock + chunkSize - 1n; + return candidate > latestBlock ? latestBlock : candidate; + })(); + + const rawLogs = await params.publicClient.getLogs({ + address: params.delegatorAddress, + fromBlock, + toBlock, + }); + + for (const log of rawLogs) { + const topic0 = log.topics?.[0] as string | undefined; + if (!topic0 || !UNIVERSAL_DELEGATOR_EVENT_TOPICS.has(topic0)) continue; + + const decoded = decodeEventLog({ + abi: UNIVERSAL_DELEGATOR_EVENT_ABI as never, + data: log.data, + topics: log.topics, + }); + + if (decoded.eventName === "CreateSlot") { + const args = decoded.args as unknown as { index: bigint; size: bigint }; + const index = args.index; + const size = args.size; + slots.set(index, { size, isShared: false }); + const parentIndex = getParentIndex(index); + ensureChildren(childrenByParent, parentIndex).push(index); + continue; + } + + if (decoded.eventName === "SetSize") { + const args = decoded.args as unknown as { index: bigint; size: bigint }; + const index = args.index; + const size = args.size; + const existing = slots.get(index); + if (existing) slots.set(index, { ...existing, size }); + continue; + } + + if (decoded.eventName === "SetIsShared") { + const args = decoded.args as unknown as { index: bigint; isShared: boolean }; + const index = args.index; + const isShared = args.isShared; + const existing = slots.get(index); + if (existing) slots.set(index, { ...existing, isShared }); + continue; + } + + if (decoded.eventName === "SwapSlots") { + const args = decoded.args as unknown as { index1: bigint; index2: bigint }; + const index1 = args.index1; + const index2 = args.index2; + const parentIndex = getParentIndex(index1); + if (parentIndex !== getParentIndex(index2)) continue; + const siblings = childrenByParent.get(parentIndex); + if (!siblings) continue; + const i1 = siblings.indexOf(index1); + const i2 = siblings.indexOf(index2); + if (i1 === -1 || i2 === -1) continue; + [siblings[i1], siblings[i2]] = [siblings[i2]!, siblings[i1]!]; + continue; + } + + if (decoded.eventName === "AssignNetwork") { + const args = decoded.args as unknown as { index: bigint; subnetwork: Hex }; + const index = args.index; + const subnetwork = args.subnetwork; + const key = subnetwork.toLowerCase(); + subnetworkToSlot.set(key, index); + networkBySlot.set(index, subnetwork); + continue; + } + + if (decoded.eventName === "UnassignNetwork") { + const args = decoded.args as unknown as { subnetwork: Hex }; + const subnetwork = args.subnetwork; + const key = subnetwork.toLowerCase(); + const prevIndex = subnetworkToSlot.get(key); + if (prevIndex !== undefined) networkBySlot.delete(prevIndex); + subnetworkToSlot.delete(key); + continue; + } + + if (decoded.eventName === "AssignOperator") { + const args = decoded.args as unknown as { index: bigint; operator: Address }; + const index = args.index; + const operator = args.operator; + operatorBySlot.set(index, operator); + continue; + } + + if (decoded.eventName === "UnassignOperator") { + const args = decoded.args as unknown as { index: bigint }; + const index = args.index; + operatorBySlot.delete(index); + continue; + } + } + } + + const groupIndices = childrenByParent.get(0n) ?? []; + const applyIsShared = (groupIndex: bigint, slotData: unknown) => { + const slot = slots.get(groupIndex); + if (!slot) return; + const isSharedTrace = + (slotData as { isShared?: unknown })?.isShared ?? (Array.isArray(slotData) ? slotData[2] : undefined); + const isSharedValue = latestTrace208Value(isSharedTrace); + slots.set(groupIndex, { ...slot, isShared: isSharedValue > 0n }); + }; + + if (groupIndices.length > 0) { + const batchSize = 100; + let canUseMulticall = true; + for (let i = 0; i < groupIndices.length; i += batchSize) { + const batch = groupIndices.slice(i, i + batchSize); + if (canUseMulticall) { + try { + const results = await params.publicClient.multicall({ + allowFailure: true, + contracts: batch.map((groupIndex) => ({ + address: params.delegatorAddress, + abi: universalDelegatorAbi, + functionName: "slots", + args: [groupIndex], + })), + }); + results.forEach((result, idx) => { + if (result.status !== "success") return; + const groupIndex = batch[idx]; + if (groupIndex === undefined) return; + applyIsShared(groupIndex, result.result); + }); + continue; + } catch { + canUseMulticall = false; + } + } + + for (const groupIndex of batch) { + const slot = slots.get(groupIndex); + if (!slot) continue; + try { + const slotData = await params.publicClient.readContract({ + abi: universalDelegatorAbi, + address: params.delegatorAddress, + functionName: "slots", + args: [groupIndex], + }); + applyIsShared(groupIndex, slotData); + } catch { + // ignore single-slot failures during reconstruction + } + } + } + } + + const groups: GroupSlot[] = []; + for (const groupIndex of groupIndices) { + const groupSlot = slots.get(groupIndex); + if (!groupSlot) continue; + + const groupDraft: GroupDraft = { size: groupSlot.size.toString(), isShared: groupSlot.isShared }; + const group: GroupSlot = { + id: `group-${formatIndex(groupIndex)}`, + index: groupIndex, + state: { draft: groupDraft, synced: { ...groupDraft } }, + networks: [], + }; + + const networkIndices = childrenByParent.get(groupIndex) ?? []; + for (const networkIndex of networkIndices) { + const networkSlot = slots.get(networkIndex); + if (!networkSlot) continue; + + const subnetwork = networkBySlot.get(networkIndex) ?? ""; + const networkDraft: NetworkDraft = { size: networkSlot.size.toString(), subnetwork }; + const network: NetworkSlot = { + id: `network-${formatIndex(networkIndex)}`, + index: networkIndex, + state: { draft: networkDraft, synced: { ...networkDraft } }, + operators: [], + }; + + const operatorIndices = childrenByParent.get(networkIndex) ?? []; + for (const operatorIndex of operatorIndices) { + const operatorSlot = slots.get(operatorIndex); + if (!operatorSlot) continue; + + const operator = operatorBySlot.get(operatorIndex) ?? ""; + const operatorDraft: OperatorDraft = { size: operatorSlot.size.toString(), operator }; + network.operators.push({ + id: `operator-${formatIndex(operatorIndex)}`, + index: operatorIndex, + state: { draft: operatorDraft, synced: { ...operatorDraft } }, + }); + } + + group.networks.push(network); + } + + groups.push(group); + } + + return { groups }; +} + +export function flexGrowFromSize(size: bigint, total: bigint): number { + if (total <= 0n) return 1; + if (size <= 0n) return 0; + const scaled = (size * 1_000_000n) / total; + if (scaled <= 0n) return 0.000001; + return Number(scaled) / 1_000_000; +} + +export function percentWidthFromSize(size: bigint, max: bigint, minPct = 40, maxPct = 100): number { + if (max <= 0n) return maxPct; + if (size <= 0n) return minPct; + const scaled = Number((size * 10_000n) / max) / 10_000; + return minPct + scaled * (maxPct - minPct); +} + +export function autoSyncAll(model: UniversalDelegatorModel): { model: UniversalDelegatorModel; ops: UdOperation[] } { + const nextModel = cloneModel(model); + const nextOps: UdOperation[] = []; + + for (const group of nextModel.groups) { + // ---------- Group ---------- + { + const draft = group.state.draft; + const size = parseUint(draft.size); + + if (size !== null) { + const synced = group.state.synced; + const syncedSize = synced ? parseUint(synced.size) : null; + const sizeDirty = synced === null || syncedSize === null || syncedSize !== size; + const isDirty = synced === null || synced.isShared !== draft.isShared || sizeDirty; + + if (synced === null || isDirty) { + if (group.index === null) { + const localIndex = BigInt(nextModel.groups.filter((g) => g.index !== null).length + 1); + group.index = createIndex(0n, localIndex); + nextOps.push({ kind: "createSlot", parentIndex: 0n, isShared: draft.isShared, size, slotId: group.id }); + } else { + if (synced && synced.isShared !== draft.isShared) { + nextOps.push({ kind: "setIsShared", index: group.index, isShared: draft.isShared }); + } + if (synced && sizeDirty) { + nextOps.push({ kind: "setSize", index: group.index, size }); + } + } + group.state.synced = { ...draft }; + } + } + } + + // ---------- Networks ---------- + for (const network of group.networks) { + const draft = network.state.draft; + const size = parseUint(draft.size); + if (size === null) continue; + if (group.index === null) continue; + + const subnetworkTrimmed = draft.subnetwork.trim(); + const subnetworkParsed = subnetworkTrimmed === "" ? null : parseBytes32(subnetworkTrimmed); + const subnetworkValid = subnetworkTrimmed === "" || subnetworkParsed !== null; + + const synced = network.state.synced; + const syncedSize = synced ? parseUint(synced.size) : null; + const isSizeDirty = synced === null || syncedSize === null || syncedSize !== size; + const isSubnetworkDirty = + subnetworkValid && (synced === null || synced.subnetwork.trim() !== subnetworkTrimmed); + + if (synced === null || isSizeDirty || isSubnetworkDirty) { + if (network.index === null) { + const localIndex = BigInt(group.networks.filter((n) => n.index !== null).length + 1); + network.index = createIndex(group.index, localIndex); + nextOps.push({ + kind: "createSlot", + parentIndex: group.index, + isShared: false, + size, + slotId: network.id, + }); + if (subnetworkParsed) { + nextOps.push({ kind: "assignNetwork", index: network.index, subnetwork: subnetworkParsed }); + } + } else { + if (synced && isSizeDirty) { + nextOps.push({ kind: "setSize", index: network.index, size }); + } + + if (synced && isSubnetworkDirty) { + const prevTrimmed = synced.subnetwork.trim(); + const nextTrimmed = subnetworkTrimmed; + if (prevTrimmed !== nextTrimmed) { + const prevParsed = prevTrimmed === "" ? null : parseBytes32(prevTrimmed); + if (prevParsed) nextOps.push({ kind: "unassignNetwork", subnetwork: prevParsed }); + if (subnetworkParsed) { + nextOps.push({ kind: "assignNetwork", index: network.index, subnetwork: subnetworkParsed }); + } + } + } + } + + if (synced === null) { + network.state.synced = { + ...draft, + subnetwork: subnetworkValid ? draft.subnetwork : "", + }; + } else { + network.state.synced = { + size: draft.size, + subnetwork: subnetworkValid ? draft.subnetwork : synced.subnetwork, + }; + } + } + + if (network.index === null) continue; + + // ---------- Operators ---------- + for (const operator of network.operators) { + const draftOp = operator.state.draft; + const sizeOp = parseUint(draftOp.size); + if (sizeOp === null) continue; + + const operatorTrimmed = draftOp.operator.trim(); + const operatorValid = operatorTrimmed === "" || isAddress(operatorTrimmed); + + const syncedOp = operator.state.synced; + const syncedSize = syncedOp ? parseUint(syncedOp.size) : null; + const isSizeDirtyOp = syncedOp === null || syncedSize === null || syncedSize !== sizeOp; + const isOperatorDirtyOp = + operatorValid && + (syncedOp === null || syncedOp.operator.trim().toLowerCase() !== operatorTrimmed.toLowerCase()); + + if (syncedOp !== null && !isSizeDirtyOp && !isOperatorDirtyOp) continue; + + if (operator.index === null) { + const localIndex = BigInt(network.operators.filter((o) => o.index !== null).length + 1); + operator.index = createIndex(network.index, localIndex); + nextOps.push({ + kind: "createSlot", + parentIndex: network.index, + isShared: false, + size: sizeOp, + slotId: operator.id, + }); + if (operatorValid && operatorTrimmed) { + nextOps.push({ kind: "assignOperator", index: operator.index, operator: operatorTrimmed as Address }); + } + } else { + if (syncedOp && isSizeDirtyOp) { + nextOps.push({ kind: "setSize", index: operator.index, size: sizeOp }); + } + + if (syncedOp && isOperatorDirtyOp) { + const prevTrimmed = syncedOp.operator.trim(); + const nextTrimmed = operatorTrimmed; + if (prevTrimmed.toLowerCase() !== nextTrimmed.toLowerCase()) { + if (prevTrimmed && isAddress(prevTrimmed)) { + nextOps.push({ + kind: "unassignOperator", + parentIndex: network.index, + operator: prevTrimmed as Address, + }); + } + if (nextTrimmed) { + nextOps.push({ kind: "assignOperator", index: operator.index, operator: nextTrimmed as Address }); + } + } + } + } + + if (syncedOp === null) { + operator.state.synced = { ...draftOp, operator: operatorValid ? draftOp.operator : "" }; + } else { + operator.state.synced = { + size: draftOp.size, + operator: operatorValid ? draftOp.operator : syncedOp.operator, + }; + } + } + } + } + + return { model: nextModel, ops: nextOps }; +} + +type SimSlot = { size: bigint; isShared: boolean }; + +type SimState = { + children: Map; + slots: Map; + created: Set; + networkToSlot: Map; + operatorBySlot: Map; + operatorToSlot: Map; + nextChildLocalIndex: Map; +}; + +export function bigintCompare(a: bigint, b: bigint): number { + if (a < b) return -1; + if (a > b) return 1; + return 0; +} + +export function shallowOptimizeOps(ops: UdOperation[]): UdOperation[] { + const out: UdOperation[] = []; + for (const op of ops) { + const last = out[out.length - 1]; + if (!last) { + out.push(op); + continue; + } + + if (last.kind === "setSize" && op.kind === "setSize" && last.index === op.index) { + out[out.length - 1] = op; + continue; + } + + if (last.kind === "setIsShared" && op.kind === "setIsShared" && last.index === op.index) { + out[out.length - 1] = op; + continue; + } + + if ( + last.kind === "swapSlots" && + op.kind === "swapSlots" && + last.index1 === op.index2 && + last.index2 === op.index1 + ) { + out.pop(); + continue; + } + + out.push(op); + } + + return out; +} + +export function mergeOps(prevOps: UdOperation[], nextOps: UdOperation[]): UdOperation[] { + if (nextOps.length === 0) return prevOps; + const merged = prevOps.slice(); + for (const op of nextOps) { + if (op.kind === "createSlot" && op.slotId) { + const existingIndex = merged.findIndex((item) => item.kind === "createSlot" && item.slotId === op.slotId); + if (existingIndex !== -1) { + merged[existingIndex] = { ...merged[existingIndex], ...op }; + continue; + } + } + merged.push(op); + } + return merged; +} + +function cloneSimState(state: SimState): SimState { + return { + children: new Map([...state.children.entries()].map(([k, v]) => [k, v.slice()])), + slots: new Map([...state.slots.entries()].map(([k, v]) => [k, { ...v }])), + created: new Set(state.created), + networkToSlot: new Map(state.networkToSlot), + operatorBySlot: new Map(state.operatorBySlot), + operatorToSlot: new Map(state.operatorToSlot), + nextChildLocalIndex: new Map(state.nextChildLocalIndex), + }; +} + +export function buildSimStateFromModel(model: UniversalDelegatorModel): SimState { + const state: SimState = { + children: new Map([[0n, []]]), + slots: new Map(), + created: new Set([0n]), + networkToSlot: new Map(), + operatorBySlot: new Map(), + operatorToSlot: new Map(), + nextChildLocalIndex: new Map(), + }; + + for (const group of model.groups) { + if (group.index === null) continue; + const groupIndex = group.index; + const groupSynced = group.state.synced; + const groupSize = parseUint(groupSynced?.size ?? group.state.draft.size) ?? 0n; + const groupIsShared = groupSynced?.isShared ?? group.state.draft.isShared; + + state.created.add(groupIndex); + state.slots.set(groupIndex, { size: groupSize, isShared: groupIsShared }); + state.children.get(0n)!.push(groupIndex); + if (!state.children.has(groupIndex)) state.children.set(groupIndex, []); + + for (const network of group.networks) { + if (network.index === null) continue; + const networkIndex = network.index; + const networkSynced = network.state.synced; + const networkSize = parseUint(networkSynced?.size ?? network.state.draft.size) ?? 0n; + + state.created.add(networkIndex); + state.slots.set(networkIndex, { size: networkSize, isShared: false }); + state.children.get(groupIndex)!.push(networkIndex); + if (!state.children.has(networkIndex)) state.children.set(networkIndex, []); + + const subnetworkRaw = (networkSynced?.subnetwork ?? network.state.draft.subnetwork).trim(); + const subnetworkParsed = subnetworkRaw === "" ? null : parseBytes32(subnetworkRaw); + if (subnetworkParsed) { + state.networkToSlot.set(subnetworkParsed.toLowerCase(), networkIndex); + } + + for (const operator of network.operators) { + if (operator.index === null) continue; + const operatorIndex = operator.index; + const operatorSynced = operator.state.synced; + const operatorSize = parseUint(operatorSynced?.size ?? operator.state.draft.size) ?? 0n; + + state.created.add(operatorIndex); + state.slots.set(operatorIndex, { size: operatorSize, isShared: false }); + state.children.get(networkIndex)!.push(operatorIndex); + if (!state.children.has(operatorIndex)) state.children.set(operatorIndex, []); + + const operatorRaw = (operatorSynced?.operator ?? operator.state.draft.operator).trim(); + if (operatorRaw !== "" && isAddress(operatorRaw)) { + const normalized = operatorRaw.toLowerCase(); + state.operatorBySlot.set(operatorIndex, operatorRaw as Address); + state.operatorToSlot.set(`${networkIndex.toString()}:${normalized}`, operatorIndex); + } + } + } + } + + for (const [parentIndex, children] of state.children.entries()) { + let maxChild = 0n; + for (const child of children) maxChild = bigintMax(maxChild, getChildIndex(child)); + state.nextChildLocalIndex.set(parentIndex, maxChild + 1n); + } + + if (!state.nextChildLocalIndex.has(0n)) state.nextChildLocalIndex.set(0n, 1n); + + return state; +} + +export function simulateOpsFromState(initial: SimState, ops: UdOperation[]): SimState | null { + const state = cloneSimState(initial); + + for (const op of ops) { + if (op.kind === "createSlot") { + const local = state.nextChildLocalIndex.get(op.parentIndex) ?? 1n; + let index: bigint; + try { + index = createIndex(op.parentIndex, local); + } catch { + return null; + } + + state.nextChildLocalIndex.set(op.parentIndex, local + 1n); + state.created.add(index); + state.slots.set(index, { size: op.size, isShared: op.isShared }); + + if (!state.children.has(op.parentIndex)) state.children.set(op.parentIndex, []); + state.children.get(op.parentIndex)!.push(index); + if (!state.children.has(index)) state.children.set(index, []); + continue; + } + + if (op.kind === "setIsShared") { + const prev = state.slots.get(op.index) ?? { size: 0n, isShared: false }; + state.slots.set(op.index, { ...prev, isShared: op.isShared }); + continue; + } + + if (op.kind === "setSize") { + const prev = state.slots.get(op.index) ?? { size: 0n, isShared: false }; + state.slots.set(op.index, { ...prev, size: op.size }); + continue; + } + + if (op.kind === "swapSlots") { + const parent = getParentIndex(op.index1); + const list = state.children.get(parent); + if (!list) return null; + const i1 = list.indexOf(op.index1); + const i2 = list.indexOf(op.index2); + if (i1 === -1 || i2 === -1) return null; + [list[i1], list[i2]] = [list[i2]!, list[i1]!]; + continue; + } + + if (op.kind === "assignNetwork") { + state.networkToSlot.set(op.subnetwork.toLowerCase(), op.index); + continue; + } + + if (op.kind === "unassignNetwork") { + state.networkToSlot.set(op.subnetwork.toLowerCase(), 0n); + continue; + } + + if (op.kind === "assignOperator") { + const parentIndex = getParentIndex(op.index); + const key = `${parentIndex.toString()}:${op.operator.toLowerCase()}`; + state.operatorToSlot.set(key, op.index); + state.operatorBySlot.set(op.index, op.operator); + continue; + } + + const key = `${op.parentIndex.toString()}:${op.operator.toLowerCase()}`; + const currentIndex = state.operatorToSlot.get(key) ?? 0n; + if (currentIndex !== 0n) state.operatorBySlot.delete(currentIndex); + state.operatorToSlot.set(key, 0n); + } + + return state; +} + +function computeMinimalSwaps(initial: bigint[], target: bigint[]): UdOperation[] | null { + if (initial.length !== target.length) return null; + if (initial.length < 2) return []; + + const current = initial.slice(); + const pos = new Map(); + for (let i = 0; i < current.length; i += 1) pos.set(current[i], i); + + const swaps: UdOperation[] = []; + for (let i = 0; i < target.length; i += 1) { + const desired = target[i]; + const currentAt = current[i]; + if (currentAt === desired) continue; + + const j = pos.get(desired); + if (j === undefined) return null; + if (j < i) return null; + + swaps.push({ kind: "swapSlots", index1: currentAt, index2: desired }); + + current[i] = desired; + current[j] = currentAt; + pos.set(currentAt, j); + pos.set(desired, i); + } + + return swaps; +} + +function compileMinimalOpsFromInitialAndFinal(params: { initial: SimState; final: SimState }): UdOperation[] | null { + const initialExisting = new Set(params.initial.slots.keys()); + const createOps: UdOperation[] = []; + const swapOps: UdOperation[] = []; + const setOps: UdOperation[] = []; + const assignOps: UdOperation[] = []; + + function slotOrDefault(index: bigint): SimSlot { + return params.final.slots.get(index) ?? { size: 0n, isShared: false }; + } + + function buildCreates(parentIndex: bigint, depth: number) { + if (depth >= 3) return; + + const initialChildren = params.initial.children.get(parentIndex) ?? []; + const finalChildren = params.final.children.get(parentIndex) ?? []; + const finalSet = new Set(finalChildren); + + const existingChildrenInOrder = initialChildren.filter((child) => finalSet.has(child)); + const newChildren = finalChildren.filter((child) => !initialExisting.has(child)); + const newChildrenSorted = newChildren.slice().sort((a, b) => bigintCompare(getChildIndex(a), getChildIndex(b))); + + const creationOrder = [...existingChildrenInOrder, ...newChildrenSorted]; + for (const child of creationOrder) { + if (!initialExisting.has(child)) { + const slot = slotOrDefault(child); + createOps.push({ + kind: "createSlot", + parentIndex, + isShared: parentIndex === 0n ? slot.isShared : false, + size: slot.size, + }); + } + buildCreates(child, depth + 1); + } + } + + buildCreates(0n, 0); + + for (const [parentIndex, finalChildren] of params.final.children.entries()) { + const initialChildren = params.initial.children.get(parentIndex) ?? []; + const finalSet = new Set(finalChildren); + + const existingChildrenInOrder = initialChildren.filter((child) => finalSet.has(child)); + const newChildren = finalChildren.filter((child) => !initialExisting.has(child)); + const newChildrenSorted = newChildren.slice().sort((a, b) => bigintCompare(getChildIndex(a), getChildIndex(b))); + + const initialAfterCreate = [...existingChildrenInOrder, ...newChildrenSorted]; + const swaps = computeMinimalSwaps(initialAfterCreate, finalChildren); + if (swaps === null) return null; + swapOps.push(...swaps); + } + + for (const [index, finalSlot] of params.final.slots.entries()) { + if (!initialExisting.has(index)) continue; + const initialSlot = params.initial.slots.get(index) ?? { size: 0n, isShared: false }; + if (initialSlot.size !== finalSlot.size) { + setOps.push({ kind: "setSize", index, size: finalSlot.size }); + } + if (getParentIndex(index) === 0n && initialSlot.isShared !== finalSlot.isShared) { + setOps.push({ kind: "setIsShared", index, isShared: finalSlot.isShared }); + } + } + + const allSubnetworks = new Set(); + for (const key of params.initial.networkToSlot.keys()) allSubnetworks.add(key); + for (const key of params.final.networkToSlot.keys()) allSubnetworks.add(key); + const subnetworkKeys = [...allSubnetworks].sort((a, b) => (a < b ? -1 : a > b ? 1 : 0)); + for (const subnetwork of subnetworkKeys) { + const initialIndex = params.initial.networkToSlot.get(subnetwork) ?? 0n; + const finalIndex = params.final.networkToSlot.get(subnetwork) ?? 0n; + if (initialIndex === finalIndex) continue; + if (initialIndex !== 0n) assignOps.push({ kind: "unassignNetwork", subnetwork: subnetwork as Hex }); + if (finalIndex !== 0n) assignOps.push({ kind: "assignNetwork", index: finalIndex, subnetwork: subnetwork as Hex }); + } + + const allOperators = new Set(); + for (const key of params.initial.operatorToSlot.keys()) allOperators.add(key); + for (const key of params.final.operatorToSlot.keys()) allOperators.add(key); + const operatorKeys = [...allOperators].sort((a, b) => (a < b ? -1 : a > b ? 1 : 0)); + for (const key of operatorKeys) { + const initialIndex = params.initial.operatorToSlot.get(key) ?? 0n; + const finalIndex = params.final.operatorToSlot.get(key) ?? 0n; + if (initialIndex === finalIndex) continue; + + const [parentStr, operator] = key.split(":"); + if (!parentStr || !operator) continue; + let parentIndex: bigint; + try { + parentIndex = BigInt(parentStr); + } catch { + continue; + } + if (initialIndex !== 0n) { + assignOps.push({ kind: "unassignOperator", parentIndex, operator: operator as Address }); + } + if (finalIndex !== 0n) { + assignOps.push({ kind: "assignOperator", index: finalIndex, operator: operator as Address }); + } + } + + return [...createOps, ...swapOps, ...setOps, ...assignOps]; +} + +export function compileOpsFromModels(params: { + baselineModel: UniversalDelegatorModel; + nextModel: UniversalDelegatorModel; +}): UdOperation[] | null { + const initial = buildSimStateFromModel(params.baselineModel); + const final = buildSimStateFromModel(params.nextModel); + return compileMinimalOpsFromInitialAndFinal({ initial, final }); +} + +export type MulticallCandidate = { label: string; ops: UdOperation[] }; + +export function opsKey(ops: UdOperation[]): string { + return JSON.stringify(ops.map(opToJson)); +} + +export function buildMulticallCandidates(params: { + ops: UdOperation[]; + baselineModel: UniversalDelegatorModel; +}): MulticallCandidate[] { + const candidates: MulticallCandidate[] = []; + const seen = new Set(); + + function push(label: string, list: UdOperation[]) { + const key = opsKey(list); + if (seen.has(key)) return; + seen.add(key); + candidates.push({ label, ops: list }); + } + + if (params.ops.length === 0) return candidates; + + const initial = buildSimStateFromModel(params.baselineModel); + const final = simulateOpsFromState(initial, params.ops); + if (final) { + const compiled = compileMinimalOpsFromInitialAndFinal({ initial, final }); + if (compiled) { + push("optimized", compiled); + } + } + + push("shallow", shallowOptimizeOps(params.ops)); + push("raw", params.ops); + + return candidates; +} + +function candidatePriority(label: string): number { + if (label === "optimized") return 0; + if (label === "shallow") return 1; + return 2; +} + +export function orderMulticallCandidates(candidates: MulticallCandidate[]): MulticallCandidate[] { + return candidates + .slice() + .sort((a, b) => a.ops.length - b.ops.length || candidatePriority(a.label) - candidatePriority(b.label)); +} + +export function encodeOpsToCalls(ops: UdOperation[]): Hex[] { + const calls: Hex[] = []; + for (const op of ops) { + if (op.kind === "createSlot") { + calls.push( + encodeFunctionData({ + abi: universalDelegatorAbi, + functionName: "createSlot", + args: [op.parentIndex, op.isShared, op.size], + }), + ); + } else if (op.kind === "setIsShared") { + calls.push( + encodeFunctionData({ + abi: universalDelegatorAbi, + functionName: "setIsShared", + args: [op.index, op.isShared], + }), + ); + } else if (op.kind === "setSize") { + calls.push( + encodeFunctionData({ + abi: universalDelegatorAbi, + functionName: "setSize", + args: [op.index, op.size], + }), + ); + } else if (op.kind === "swapSlots") { + calls.push( + encodeFunctionData({ + abi: universalDelegatorAbi, + functionName: "swapSlots", + args: [op.index1, op.index2], + }), + ); + } else if (op.kind === "assignNetwork") { + calls.push( + encodeFunctionData({ + abi: universalDelegatorAbi, + functionName: "assignNetwork", + args: [op.index, op.subnetwork], + }), + ); + } else if (op.kind === "unassignNetwork") { + calls.push( + encodeFunctionData({ + abi: universalDelegatorAbi, + functionName: "unassignNetwork", + args: [op.subnetwork], + }), + ); + } else if (op.kind === "assignOperator") { + calls.push( + encodeFunctionData({ + abi: universalDelegatorAbi, + functionName: "assignOperator", + args: [op.index, op.operator], + }), + ); + } else { + calls.push( + encodeFunctionData({ + abi: universalDelegatorAbi, + functionName: "unassignOperator", + args: [op.parentIndex, op.operator], + }), + ); + } + } + return calls; +} + +export function formatViemError(error: unknown): string { + if (error instanceof ContractFunctionRevertedError) { + const data = error.data; + if (data?.errorName) { + if (data.args && data.args.length > 0) { + const args = data.args.map((arg) => String(arg)).join(", "); + return `${data.errorName}(${args})`; + } + return data.errorName; + } + if (error.reason) return error.reason; + } + if (error instanceof BaseError) return error.shortMessage ?? error.message; + if (error instanceof Error) return error.message; + return "Unknown error"; +} + +export function extractRevertName(error: unknown): string | null { + if (error instanceof ContractFunctionRevertedError) return error.data?.errorName ?? null; + if (error instanceof BaseError) { + const nested = error.walk((err) => err instanceof ContractFunctionRevertedError); + if (nested instanceof ContractFunctionRevertedError) return nested.data?.errorName ?? null; + } + return null; +} + +type CandidateSimulationResult = { + candidate: MulticallCandidate; + status: "success" | "failure"; + error?: unknown; +}; + +function computeSimulatedAllocationsFromState(state: SimState, rootBalance: bigint): Map { + const allocated = new Map(); + allocated.set(0n, rootBalance); + + const walk = (parentIndex: bigint) => { + const children = state.children.get(parentIndex) ?? []; + const parentAllocated = allocated.get(parentIndex) ?? 0n; + const parentSlot = state.slots.get(parentIndex); + const parentIsShared = parentIndex === 0n ? false : (parentSlot?.isShared ?? false); + + let prevSum = 0n; + for (const child of children) { + const childSlot = state.slots.get(child) ?? { size: 0n, isShared: false }; + const childAllocated = parentIsShared + ? bigintMin(parentAllocated, childSlot.size) + : bigintMin(saturatingSub(parentAllocated, prevSum), childSlot.size); + allocated.set(child, childAllocated); + prevSum += childSlot.size; + walk(child); + } + }; + + walk(0n); + return allocated; +} + +export function describeNotEnoughAvailable(params: { + ops: UdOperation[]; + failureIndex: number; + baselineModel: UniversalDelegatorModel; + rootBalance: bigint | null; +}): string | null { + const failing = params.ops[params.failureIndex]; + if (!failing || failing.kind !== "setSize") return null; + + const initial = buildSimStateFromModel(params.baselineModel); + const before = simulateOpsFromState(initial, params.ops.slice(0, params.failureIndex)); + if (!before) return null; + + const prevSize = before.slots.get(failing.index)?.size ?? 0n; + if (failing.size <= prevSize) return null; + const increase = failing.size - prevSize; + + const parentIndex = getParentIndex(failing.index); + const parentDepth = getDepth(parentIndex); + const childDepth = getDepth(failing.index); + const parentLabel = + parentDepth === 0 + ? "root" + : parentDepth === 1 + ? `Group #${getChildIndex(parentIndex)}` + : `Network #${getChildIndex(parentIndex)}`; + const childLabel = childDepth === 1 ? "Group" : childDepth === 2 ? "Network" : "Operator"; + + const children = before.children.get(parentIndex) ?? []; + let childrenSize = 0n; + for (const child of children) { + childrenSize += before.slots.get(child)?.size ?? 0n; + } + + let available: bigint | null = null; + if (parentIndex === 0n) { + available = params.rootBalance; + } else if (params.rootBalance !== null) { + const allocated = computeSimulatedAllocationsFromState(before, params.rootBalance); + available = allocated.get(parentIndex) ?? null; + } + if (available === null) { + available = before.slots.get(parentIndex)?.size ?? null; + } + if (available === null) return null; + + const unallocated = saturatingSub(available, childrenSize); + if (increase <= unallocated) return null; + return `${childLabel} size increase by ${increase.toString()} in ${parentLabel} exceeds available ${unallocated.toString()}.`; +} + +export async function simulateMulticallCandidates(params: { + publicClient: PublicClient; + delegatorAddress: Address; + account: Address; + candidates: MulticallCandidate[]; +}): Promise { + if (params.candidates.length === 0) return []; + const calls = params.candidates.map((candidate) => ({ + to: params.delegatorAddress, + abi: universalDelegatorAbi, + functionName: "multicall", + args: [encodeOpsToCalls(candidate.ops)], + })); + const { results } = await params.publicClient.simulateCalls({ + account: params.account, + calls, + }); + return results.map((result, index) => ({ + candidate: params.candidates[index]!, + status: result.status, + error: result.status === "failure" ? result.error : undefined, + })); +} + +export async function simulateMulticall(params: { + publicClient: PublicClient; + delegatorAddress: Address; + account: Address; + calls: Hex[]; +}): Promise { + if (params.calls.length === 0) return; + await params.publicClient.simulateContract({ + address: params.delegatorAddress, + abi: universalDelegatorAbi, + functionName: "multicall", + args: [params.calls], + account: params.account, + }); +} + +export async function findFailingOp(params: { + publicClient: PublicClient; + delegatorAddress: Address; + account: Address; + ops: UdOperation[]; +}): Promise<{ index: number; error: unknown } | null> { + if (params.ops.length === 0) return null; + const calls = encodeOpsToCalls(params.ops); + if (calls.length === 0) return null; + + let low = 0; + let high = calls.length - 1; + let failure: { index: number; error: unknown } | null = null; + + while (low <= high) { + const mid = Math.floor((low + high) / 2); + try { + await simulateMulticall({ + publicClient: params.publicClient, + delegatorAddress: params.delegatorAddress, + account: params.account, + calls: calls.slice(0, mid + 1), + }); + low = mid + 1; + } catch (error) { + failure = { index: mid, error }; + high = mid - 1; + } + } + + return failure; +} + +export function opsBaselineModel(params: { + model: UniversalDelegatorModel; + ops: UdOperation[]; + history: Array<{ model: UniversalDelegatorModel; ops: UdOperation[] }>; +}): UniversalDelegatorModel { + if (params.ops.length === 0) return params.model; + for (let i = params.history.length - 1; i >= 0; i -= 1) { + const snapshot = params.history[i]; + if (snapshot && snapshot.ops.length === 0) return snapshot.model; + } + return params.history[0]?.model ?? params.model; +} + +export function formatOp(op: UdOperation): string { + if (op.kind === "createSlot") { + return `createSlot(${formatIndex(op.parentIndex)}, ${op.isShared}, ${op.size})`; + } + if (op.kind === "setIsShared") { + return `setIsShared(${formatIndex(op.index)}, ${op.isShared})`; + } + if (op.kind === "setSize") { + return `setSize(${formatIndex(op.index)}, ${op.size})`; + } + if (op.kind === "swapSlots") { + return `swapSlots(${formatIndex(op.index1)}, ${formatIndex(op.index2)})`; + } + if (op.kind === "assignNetwork") { + return `assignNetwork(${formatIndex(op.index)}, ${op.subnetwork})`; + } + if (op.kind === "unassignNetwork") { + return `unassignNetwork(${op.subnetwork})`; + } + if (op.kind === "assignOperator") { + return `assignOperator(${formatIndex(op.index)}, ${op.operator})`; + } + return `unassignOperator(${formatIndex(op.parentIndex)}, ${op.operator})`; +} + +export function opToJson(op: UdOperation): Record { + if (op.kind === "createSlot") { + return { + kind: op.kind, + parentIndex: formatIndex(op.parentIndex), + isShared: op.isShared, + size: op.size.toString(), + }; + } + if (op.kind === "setIsShared") { + return { kind: op.kind, index: formatIndex(op.index), isShared: op.isShared }; + } + if (op.kind === "setSize") { + return { kind: op.kind, index: formatIndex(op.index), size: op.size.toString() }; + } + if (op.kind === "swapSlots") { + return { + kind: op.kind, + index1: formatIndex(op.index1), + index2: formatIndex(op.index2), + }; + } + if (op.kind === "assignNetwork") { + return { kind: op.kind, index: formatIndex(op.index), subnetwork: op.subnetwork }; + } + if (op.kind === "unassignNetwork") { + return { kind: op.kind, subnetwork: op.subnetwork }; + } + if (op.kind === "assignOperator") { + return { kind: op.kind, index: formatIndex(op.index), operator: op.operator }; + } + return { + kind: op.kind, + parentIndex: formatIndex(op.parentIndex), + operator: op.operator, + }; +} From 339104bd87424b995c7b36ff4f6c24215be3a98b Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 23 Dec 2025 22:22:46 +0400 Subject: [PATCH 04/10] refactor: simplify calculations --- .../pages/UniversalDelegatorConfigurator.tsx | 42 +++++++------------ 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/ui/src/pages/UniversalDelegatorConfigurator.tsx b/ui/src/pages/UniversalDelegatorConfigurator.tsx index e3daa9e1..2d22da43 100644 --- a/ui/src/pages/UniversalDelegatorConfigurator.tsx +++ b/ui/src/pages/UniversalDelegatorConfigurator.tsx @@ -564,14 +564,10 @@ export function UniversalDelegatorConfigurator() { }, [model, ops]); const applyModelUpdate = useCallback( - ( - updater: (current: UniversalDelegatorModel) => UniversalDelegatorModel, - options?: { syncOps?: boolean }, - ) => { + (updater: (current: UniversalDelegatorModel) => UniversalDelegatorModel) => { pushHistorySnapshot(); setModel((prev) => { const updated = updater(prev); - if (options?.syncOps === false) return updated; const auto = autoSyncAll(updated); setOps((prevOps) => { const compiled = compileOpsFromModels({ baselineModel, nextModel: auto.model }); @@ -673,7 +669,7 @@ export function UniversalDelegatorConfigurator() { state: { draft: { size: "", isShared: false }, synced: null }, networks: [], }; - applyModelUpdate((prev) => ({ ...prev, groups: [...prev.groups, group] }), { syncOps: false }); + applyModelUpdate((prev) => ({ ...prev, groups: [...prev.groups, group] })); } function addGroupFromTemplate() { @@ -712,7 +708,7 @@ export function UniversalDelegatorConfigurator() { state: { draft: { size: "", isShared }, synced: null }, networks, }; - applyModelUpdate((prev) => ({ ...prev, groups: [...prev.groups, group] }), { syncOps: false }); + applyModelUpdate((prev) => ({ ...prev, groups: [...prev.groups, group] })); } function swapNeighborSlots() { @@ -790,13 +786,10 @@ export function UniversalDelegatorConfigurator() { operators: [], }; - applyModelUpdate( - (prev) => ({ - ...prev, - groups: prev.groups.map((g) => (g.id === groupId ? { ...g, networks: [...g.networks, network] } : g)), - }), - { syncOps: false }, - ); + applyModelUpdate((prev) => ({ + ...prev, + groups: prev.groups.map((g) => (g.id === groupId ? { ...g, networks: [...g.networks, network] } : g)), + })); } function updateNetworkDraft(groupId: string, networkId: string, patch: Partial) { @@ -825,19 +818,16 @@ export function UniversalDelegatorConfigurator() { state: { draft: { size: "", operator: "" }, synced: null }, }; - applyModelUpdate( - (prev) => ({ - ...prev, - groups: prev.groups.map((g) => { - if (g.id !== groupId) return g; - return { - ...g, - networks: g.networks.map((n) => (n.id === networkId ? { ...n, operators: [...n.operators, slot] } : n)), - }; - }), + applyModelUpdate((prev) => ({ + ...prev, + groups: prev.groups.map((g) => { + if (g.id !== groupId) return g; + return { + ...g, + networks: g.networks.map((n) => (n.id === networkId ? { ...n, operators: [...n.operators, slot] } : n)), + }; }), - { syncOps: false }, - ); + })); } function updateOperatorDraft(groupId: string, networkId: string, operatorId: string, patch: Partial) { From 22faa047334dab90e097e5c1ccf2223713dc9681 Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 23 Dec 2025 22:46:36 +0400 Subject: [PATCH 05/10] docs: update spec --- spec/delegator/UniversalDelegator.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/spec/delegator/UniversalDelegator.md b/spec/delegator/UniversalDelegator.md index f1b5563e..ef72efa9 100644 --- a/spec/delegator/UniversalDelegator.md +++ b/spec/delegator/UniversalDelegator.md @@ -1,7 +1,7 @@ # Universal Delegator `UniversalDelegator` is a `BaseDelegator` implementation that allocates a vault’s stake through a small ordered tree of “slots”. -Slots can be configured to allocate **exclusively** (no overlap) or **shared** (overlap / restaking) between siblings. +Slots can be configured to allocate in **isolated** mode (no overlap) or **shared** (overlap / restaking) between siblings. This document describes the contract behavior in `src/contracts/delegator/UniversalDelegator.sol`. @@ -70,7 +70,7 @@ Let: - `availableParent = getAvailable(parentIndex)` (or `getAvailableAt(parentIndex, t)`) - `cap = slots[index].size` -In exclusive mode (parent not shared), the child’s effective available is: +In isolated mode (parent not shared), the child’s effective available is: - `childAvailable = saturatingSub(availableParent, slots[index].prevSum)` @@ -95,6 +95,7 @@ Creates a new child slot under `parentIndex`: - `prevSum` is set to the current `_getChildrenSize(parentIndex)` (total size of existing children). - `isShared` is checkpointed on the new slot. - `size` is set to the provided `size`. +- `size` may be `0`, which creates a valid slot that allocates nothing until resized. `isShared = true` is only allowed when creating a depth-1 slot (i.e., `parentIndex` is the root); otherwise it reverts with `WrongDepth()`. @@ -102,7 +103,10 @@ Creates a new child slot under `parentIndex`: Updates a slot’s `size` cap. -- Increasing size is only allowed when it doesn’t exceed the parent’s currently unallocated capacity (see `NotEnoughAvailable()`). +- Increasing size is constrained only for **isolated parents** (parent `isShared == 0`) when the slot is **fully allocated** and **not the last child**. + In that case, the increase (`size - currentSize`) must fit within the parent’s unallocated balance + (`getUnallocated(parentIndex)`, i.e., `getAvailable(parentIndex)` minus the total size of its children), otherwise it reverts with `NotEnoughAvailable()`. + For shared parents, or when the slot is not fully allocated / is the last child, increases are allowed. - Decreasing size below the slot’s current allocation schedules a “pending free” amount on the parent via `pendingFreeCumulative`. - Updates `prevSum` checkpoints for following siblings using `_syncPrevSums(index)`. From e3940cd70a7afae518da6ad140216dbe5c15351c Mon Sep 17 00:00:00 2001 From: Andrey Date: Sun, 28 Dec 2025 00:39:02 +0400 Subject: [PATCH 06/10] refactor: split ui --- .../pages/UniversalDelegatorConfigurator.tsx | 667 ++++++------------ .../components/GroupCard.tsx | 84 +++ .../components/MulticallPanel.tsx | 97 +++ .../components/NetworkCard.tsx | 88 +++ .../components/OperatorCard.tsx | 67 ++ .../components/SlotIndexBadge.tsx | 14 + .../components/SlotVisuals.tsx | 74 ++ .../components/StatusBanner.tsx | 12 + .../components/WalletStatus.tsx | 40 ++ .../pages/universalDelegator/useTxStatus.ts | 38 + 10 files changed, 742 insertions(+), 439 deletions(-) create mode 100644 ui/src/pages/universalDelegator/components/GroupCard.tsx create mode 100644 ui/src/pages/universalDelegator/components/MulticallPanel.tsx create mode 100644 ui/src/pages/universalDelegator/components/NetworkCard.tsx create mode 100644 ui/src/pages/universalDelegator/components/OperatorCard.tsx create mode 100644 ui/src/pages/universalDelegator/components/SlotIndexBadge.tsx create mode 100644 ui/src/pages/universalDelegator/components/SlotVisuals.tsx create mode 100644 ui/src/pages/universalDelegator/components/StatusBanner.tsx create mode 100644 ui/src/pages/universalDelegator/components/WalletStatus.tsx create mode 100644 ui/src/pages/universalDelegator/useTxStatus.ts diff --git a/ui/src/pages/UniversalDelegatorConfigurator.tsx b/ui/src/pages/UniversalDelegatorConfigurator.tsx index 2d22da43..ebf2e150 100644 --- a/ui/src/pages/UniversalDelegatorConfigurator.tsx +++ b/ui/src/pages/UniversalDelegatorConfigurator.tsx @@ -1,10 +1,17 @@ import { usePrivy } from "@privy-io/react-auth"; -import { useCallback, useEffect, useMemo, useRef, useState, type CSSProperties, type MouseEvent } from "react"; +import { useCallback, useEffect, useMemo, useRef, useState, type MouseEvent } from "react"; import { useAccount, usePublicClient, useReadContracts, useWaitForTransactionReceipt, useWriteContract } from "wagmi"; import { type Address, BaseError, type Hex, encodeFunctionData, isAddress } from "viem"; import { universalDelegatorAbi } from "../contracts/universalDelegator"; import { formatIndex, getChildIndex } from "../utils/universalDelegatorIndex"; +import { GroupCard } from "./universalDelegator/components/GroupCard"; +import { MulticallPanel } from "./universalDelegator/components/MulticallPanel"; +import { NetworkCard } from "./universalDelegator/components/NetworkCard"; +import { OperatorCard } from "./universalDelegator/components/OperatorCard"; +import { StatusBanner } from "./universalDelegator/components/StatusBanner"; +import { AddSlotButton } from "./universalDelegator/components/SlotVisuals"; +import { WalletStatus } from "./universalDelegator/components/WalletStatus"; import { type GroupConstructor, type GroupDraft, @@ -52,8 +59,7 @@ import { simulateMulticallCandidates, sumBigints, } from "./universalDelegator/logic"; - -const FILL_OPACITY = 0.2; +import { useTxStatus } from "./universalDelegator/useTxStatus"; type SlotMetrics = { allocatedValue: bigint; @@ -62,21 +68,6 @@ type SlotMetrics = { pendingPct: number; }; -function pendingPatternStyle(colorVar: string): CSSProperties { - const lineColor = `var(${colorVar})`; - return { - backgroundImage: `linear-gradient(${lineColor} 0 2px, transparent 2px 10px), linear-gradient(90deg, ${lineColor} 0 2px, transparent 2px 10px)`, - backgroundSize: "10px 10px", - backgroundPosition: "-1px -1px", - backgroundRepeat: "repeat", - opacity: FILL_OPACITY, - }; -} - -function allocatedFillStyle(colorVar: string): CSSProperties { - return { backgroundColor: `var(${colorVar})`, opacity: FILL_OPACITY }; -} - function isInteractiveTarget(target: EventTarget | null): boolean { const element = target as HTMLElement | null; if (!element || typeof element.closest !== "function") return false; @@ -102,17 +93,25 @@ function computeSlotMetrics(params: { return { allocatedValue, pendingValue, allocatedPct, pendingPct }; } -function SlotIndexBadge(props: { index: bigint; onCopy: (index: bigint) => void }) { - return ( - - ); +function formatBalanceDisplay(params: { + canReadBalances: boolean; + hasRootBalance: boolean; + indexDefined: boolean; + loading: boolean; + value: bigint; +}): string { + if (!params.canReadBalances || !params.hasRootBalance || !params.indexDefined) return "—"; + if (params.loading) return "loading…"; + return params.value.toString(); +} + +function hasReadError(data: readonly unknown[] | undefined): boolean { + if (!data) return false; + return data.some((item) => { + if (!item || typeof item !== "object") return false; + if (!("error" in item)) return false; + return Boolean((item as { error?: unknown }).error); + }); } export function UniversalDelegatorConfigurator() { @@ -125,6 +124,7 @@ export function UniversalDelegatorConfigurator() { hash: txHash, query: { enabled: Boolean(txHash) }, }); + const txStatus = useTxStatus({ isPending, isConfirming, isConfirmed, error }); const handledTxHashRef = useRef(null); const nextId = useRef(1); @@ -547,6 +547,27 @@ export function UniversalDelegatorConfigurator() { ? allocatedLoading : canReadBalances && balancesLoading && rootBalance === null; const pendingLoading = shouldUseOnchainAllocations ? availableLoading || allocatedLoading : false; + const onchainReadActive = canReadBalances || canReadOnchainAllocations || canReadAvailable; + const hasReadErrors = useMemo( + () => hasReadError(balancesData) || hasReadError(allocatedData) || hasReadError(availableData), + [allocatedData, availableData, balancesData], + ); + const statusBanner = useMemo(() => { + if (hasReadErrors) { + return { tone: "error" as const, message: "Some on-chain reads failed. Check RPC endpoints or retry." }; + } + if (isReconstructing || (onchainReadActive && (balancesLoading || allocatedLoading || availableLoading))) { + return { tone: "info" as const, message: "Loading on-chain data..." }; + } + return null; + }, [ + allocatedLoading, + availableLoading, + balancesLoading, + hasReadErrors, + isReconstructing, + onchainReadActive, + ]); const encodedCalls = useMemo(() => encodeOpsToCalls(selectedOps), [selectedOps]); @@ -558,6 +579,10 @@ export function UniversalDelegatorConfigurator() { args: [encodedCalls], }); }, [encodedCalls]); + const handleCopyCalldata = useCallback(() => { + if (!multicallCalldata) return; + void navigator.clipboard.writeText(multicallCalldata).then(() => flashToast("Calldata copied!")); + }, [flashToast, multicallCalldata]); const pushHistorySnapshot = useCallback(() => { setHistory((prev) => [...prev, { model: cloneModel(model), ops: cloneOps(ops) }]); @@ -875,6 +900,7 @@ export function UniversalDelegatorConfigurator() { isAddress(delegatorAddress) && encodedCalls.length > 0 && !isPending && + !isConfirming && !isValidatingMulticall && !multicallError; @@ -883,7 +909,6 @@ export function UniversalDelegatorConfigurator() { const walletConnected = Boolean(authenticated && isConnected && accountAddress); const shortAccountAddress = accountAddress ? formatShortAddress(accountAddress) : ""; const chainLabel = chain?.name ?? "Unknown chain"; - const walletStatusLabel = walletConnected ? "Wallet connected" : "Wallet disconnected"; const delegatorTrimmed = delegatorAddress.trim(); const isDelegatorInvalid = delegatorTrimmed.length > 0 && !isAddress(delegatorTrimmed); const zoomCrumbs = useMemo(() => { @@ -992,117 +1017,39 @@ export function UniversalDelegatorConfigurator() {
UniversalDelegator Configurator
-
-
-
- - {walletStatusLabel} -
- {walletConnected ? ( -
- - {shortAccountAddress} - - {chainLabel} -
- ) : null} -
- {authenticated ? ( - - ) : ( - - )} -
+
-
-
-
-
-
Multicall
-
{encodedCalls.length} call(s) queued
-
- Strategy: {selectedCandidateLabel} - {selectedCandidateLabel !== primaryCandidateLabel ? " (fallback)" : null} -
-
-
- {isValidatingMulticall ? ( -
- Validating multicall against on-chain state… -
- ) : null} - -
-
- - {multicallWarning ? ( -
- {multicallWarning} -
- ) : null} - - {(isPending || isConfirming || isConfirmed || error) && ( -
- {txHash ?
{txHash}
: null} -
- {error ? ( -
{error.message}
- ) : isConfirmed ? ( -
Confirmed
- ) : isConfirming ? ( -
Waiting for confirmation…
- ) : isPending ? ( -
Waiting for wallet approval…
- ) : null} -
-
- )} - -
Ops
-
- {selectedOps.length === 0 ? ( -
No operations yet.
- ) : ( -
    - {selectedOps.map((op, i) => ( -
  1. - {formatOp(op)} -
  2. - ))} -
- )} -
- -
- - {multicallError ?
{multicallError}
: null} -
-
-
+ {statusBanner ? : null} +
@@ -1307,6 +1254,20 @@ export function UniversalDelegatorConfigurator() { pendingByIndex, }); const { allocatedValue, pendingValue, allocatedPct, pendingPct } = metrics; + const allocatedDisplay = formatBalanceDisplay({ + canReadBalances, + hasRootBalance, + indexDefined: groupIndex !== undefined, + loading: allocationsLoading || pendingLoading, + value: allocatedValue, + }); + const pendingDisplay = formatBalanceDisplay({ + canReadBalances, + hasRootBalance, + indexDefined: groupIndex !== undefined, + loading: pendingLoading, + value: pendingValue, + }); const isGroupFocused = zoom.kind !== "all" && zoom.groupId === group.id; const isGroupHovered = hoveredGroupId === group.id; const handleGroupClick = (event: MouseEvent) => { @@ -1331,129 +1292,62 @@ export function UniversalDelegatorConfigurator() { }; return ( -
updateGroupDraft(group.id, { isShared: next })} + onSizeChange={(value) => updateGroupDraft(group.id, { size: value })} + onCardClick={handleGroupClick} + onCardHover={handleGroupHover} + onCardLeave={handleGroupLeave} > -
addDraftNetwork(group.id)} + showAddNetwork={zoom.kind !== "network"} + focusedNetworkId={zoom.kind === "network" ? zoom.networkId : null} + onZoomNetwork={(networkId) => + setZoom((prev) => + prev.kind === "network" && prev.networkId === networkId + ? { kind: "group", groupId: group.id } + : { kind: "network", groupId: group.id, networkId }, + ) + } + onUpdateNetworkDraft={(networkId, patch) => updateNetworkDraft(group.id, networkId, patch)} + onAddOperator={(networkId) => addDraftOperator(group.id, networkId)} + onUpdateOperatorDraft={(networkId, operatorId, patch) => + updateOperatorDraft(group.id, networkId, operatorId, patch) + } /> - {pendingPct > 0 ? ( -
- ) : null} -
-
-
-
- {groupIndex !== undefined ? ( - - ) : null} -
Group
-
-
-
- Allocated:{" "} - {!canReadBalances || !hasRootBalance || groupIndex === undefined - ? "—" - : allocationsLoading || pendingLoading - ? "loading…" - : allocatedValue.toString()} -
-
- Pending:{" "} - {!canReadBalances || !hasRootBalance || groupIndex === undefined - ? "—" - : pendingLoading - ? "loading…" - : pendingValue.toString()} -
-
-
- -
- - - -
-
- - addDraftNetwork(group.id)} - showAddNetwork={zoom.kind !== "network"} - focusedNetworkId={zoom.kind === "network" ? zoom.networkId : null} - onZoomNetwork={(networkId) => - setZoom((prev) => - prev.kind === "network" && prev.networkId === networkId - ? { kind: "group", groupId: group.id } - : { kind: "network", groupId: group.id, networkId }, - ) - } - onUpdateNetworkDraft={(networkId, patch) => updateNetworkDraft(group.id, networkId, patch)} - onAddOperator={(networkId) => addDraftOperator(group.id, networkId)} - onUpdateOperatorDraft={(networkId, operatorId, patch) => - updateOperatorDraft(group.id, networkId, operatorId, patch) - } - /> -
-
+ ); })} {zoom.kind === "all" ? ( - + /> ) : null}
@@ -1524,6 +1418,20 @@ function NetworksRow(props: { pendingByIndex: props.pendingByIndex, }); const { allocatedValue, pendingValue, allocatedPct, pendingPct } = metrics; + const allocatedDisplay = formatBalanceDisplay({ + canReadBalances: props.canReadBalances, + hasRootBalance: props.hasRootBalance, + indexDefined: networkIndex !== undefined, + loading: props.allocationsLoading || props.pendingLoading, + value: allocatedValue, + }); + const pendingDisplay = formatBalanceDisplay({ + canReadBalances: props.canReadBalances, + hasRootBalance: props.hasRootBalance, + indexDefined: networkIndex !== undefined, + loading: props.pendingLoading, + value: pendingValue, + }); const subnetworkTrimmed = draft.subnetwork.trim(); const subnetworkValid = subnetworkTrimmed === "" || parseBytes32(subnetworkTrimmed) !== null; const isFocused = focusedNetworkId === network.id; @@ -1547,128 +1455,59 @@ function NetworksRow(props: { setHoveredNetworkId((prev) => (prev === network.id ? null : prev)); }; return ( -
props.onUpdateNetworkDraft(network.id, { subnetwork: value })} + onSizeChange={(value) => props.onUpdateNetworkDraft(network.id, { size: value })} + onCardClick={handleNetworkClick} + onCardHover={handleNetworkHover} + onCardLeave={handleNetworkLeave} > -
props.onAddOperator(network.id)} + onUpdateOperatorDraft={(operatorId, patch) => props.onUpdateOperatorDraft(network.id, operatorId, patch)} /> - {pendingPct > 0 ? ( -
- ) : null} -
-
-
-
- {networkIndex !== undefined ? ( - - ) : null} -
Network
-
-
-
- Allocated:{" "} - {!props.canReadBalances || !props.hasRootBalance || networkIndex === undefined - ? "—" - : props.allocationsLoading || props.pendingLoading - ? "loading…" - : allocatedValue.toString()} -
-
- Pending:{" "} - {!props.canReadBalances || !props.hasRootBalance || networkIndex === undefined - ? "—" - : props.pendingLoading - ? "loading…" - : pendingValue.toString()} -
-
- props.onUpdateNetworkDraft(network.id, { subnetwork: e.target.value })} - /> -
- - -
- - props.onAddOperator(network.id)} - onUpdateOperatorDraft={(operatorId, patch) => - props.onUpdateOperatorDraft(network.id, operatorId, patch) - } - /> -
-
+ ); })} {showAddNetwork ? ( - + dataNoZoom + /> ) : null}
@@ -1719,103 +1558,53 @@ function OperatorsRow(props: { pendingByIndex: props.pendingByIndex, }); const { allocatedValue, pendingValue, allocatedPct, pendingPct } = metrics; + const allocatedDisplay = formatBalanceDisplay({ + canReadBalances: props.canReadBalances, + hasRootBalance: props.hasRootBalance, + indexDefined: operatorIndex !== undefined, + loading: props.allocationsLoading || props.pendingLoading, + value: allocatedValue, + }); + const pendingDisplay = formatBalanceDisplay({ + canReadBalances: props.canReadBalances, + hasRootBalance: props.hasRootBalance, + indexDefined: operatorIndex !== undefined, + loading: props.pendingLoading, + value: pendingValue, + }); const operatorTrimmed = draft.operator.trim(); const operatorValid = operatorTrimmed === "" || isAddress(operatorTrimmed); return ( -
-
- {pendingPct > 0 ? ( -
- ) : null} -
-
-
-
- {operatorIndex !== undefined ? ( - - ) : null} -
Operator
-
-
-
- Allocated:{" "} - {!props.canReadBalances || !props.hasRootBalance || operatorIndex === undefined - ? "—" - : props.allocationsLoading || props.pendingLoading - ? "loading…" - : allocatedValue.toString()} -
-
- Pending:{" "} - {!props.canReadBalances || !props.hasRootBalance || operatorIndex === undefined - ? "—" - : props.pendingLoading - ? "loading…" - : pendingValue.toString()} -
-
- props.onUpdateOperatorDraft(operator.id, { operator: e.target.value })} - /> -
- - -
-
-
+ operator={operator} + operatorIndex={operatorIndex} + allocatedPct={allocatedPct} + pendingPct={pendingPct} + allocatedDisplay={allocatedDisplay} + pendingDisplay={pendingDisplay} + operatorGrow={operatorGrow} + sizeInvalid={draft.size.trim() !== "" && !sizeValid} + operatorInvalid={operatorTrimmed !== "" && !operatorValid} + onCopyIndex={props.onCopyIndex} + onOperatorChange={(value) => props.onUpdateOperatorDraft(operator.id, { operator: value })} + onSizeChange={(value) => props.onUpdateOperatorDraft(operator.id, { size: value })} + /> ); })} - + dataNoZoom + />
); diff --git a/ui/src/pages/universalDelegator/components/GroupCard.tsx b/ui/src/pages/universalDelegator/components/GroupCard.tsx new file mode 100644 index 00000000..debd471e --- /dev/null +++ b/ui/src/pages/universalDelegator/components/GroupCard.tsx @@ -0,0 +1,84 @@ +import type { MouseEvent, ReactNode } from "react"; + +import type { GroupSlot } from "../logic"; +import { SlotIndexBadge } from "./SlotIndexBadge"; +import { SlotBalances, SlotFill } from "./SlotVisuals"; + +type GroupCardProps = { + group: GroupSlot; + groupIndex?: bigint; + allocatedPct: number; + pendingPct: number; + allocatedDisplay: string; + pendingDisplay: string; + groupGrow: number; + isFocused: boolean; + isHovered: boolean; + sizeInvalid: boolean; + onCopyIndex: (index: bigint) => void; + onToggleShared: (next: boolean) => void; + onSizeChange: (value: string) => void; + onCardClick: (event: MouseEvent) => void; + onCardHover: (event: MouseEvent) => void; + onCardLeave: () => void; + children: ReactNode; +}; + +export function GroupCard(props: GroupCardProps) { + const draft = props.group.state.draft; + + return ( +
+ +
+
+
+
+ {props.groupIndex !== undefined ? ( + + ) : null} +
Group
+
+ +
+ +
+ + + +
+
+ + {props.children} +
+
+ ); +} diff --git a/ui/src/pages/universalDelegator/components/MulticallPanel.tsx b/ui/src/pages/universalDelegator/components/MulticallPanel.tsx new file mode 100644 index 00000000..9206114e --- /dev/null +++ b/ui/src/pages/universalDelegator/components/MulticallPanel.tsx @@ -0,0 +1,97 @@ +import type { Hex } from "viem"; + +import { formatOp, type UdOperation } from "../logic"; +import type { TxStatus } from "../useTxStatus"; + +type MulticallPanelProps = { + encodedCallsCount: number; + selectedCandidateLabel: string; + primaryCandidateLabel: string; + isValidatingMulticall: boolean; + canExecute: boolean; + isPending: boolean; + onExecute: () => void; + multicallWarning: string | null; + txHash: Hex | null | undefined; + txStatus: TxStatus; + selectedOps: UdOperation[]; + multicallErrorOp: { index: number; op: UdOperation } | null; + multicallError: string | null; + multicallCalldata: string | null; + onCopyCalldata: () => void; + hoverActionClass: string; +}; + +export function MulticallPanel(props: MulticallPanelProps) { + const statusToneClass = + props.txStatus.tone === "error" ? "text-error" : props.txStatus.tone === "success" ? "text-success" : ""; + + return ( +
+
+
+
+
Multicall
+
{props.encodedCallsCount} call(s) queued
+
+ Strategy: {props.selectedCandidateLabel} + {props.selectedCandidateLabel !== props.primaryCandidateLabel ? " (fallback)" : null} +
+
+
+ {props.isValidatingMulticall ? ( +
Validating multicall against on-chain state...
+ ) : null} + +
+
+ + {props.multicallWarning ? ( +
+ {props.multicallWarning} +
+ ) : null} + + {props.txStatus.show ? ( +
+ {props.txHash ?
{props.txHash}
: null} +
{props.txStatus.message}
+
+ ) : null} + +
Ops
+
+ {props.selectedOps.length === 0 ? ( +
No operations yet.
+ ) : ( +
    + {props.selectedOps.map((op, i) => ( +
  1. + {formatOp(op)} +
  2. + ))} +
+ )} +
+ +
+ + {props.multicallError ?
{props.multicallError}
: null} +
+
+
+ ); +} diff --git a/ui/src/pages/universalDelegator/components/NetworkCard.tsx b/ui/src/pages/universalDelegator/components/NetworkCard.tsx new file mode 100644 index 00000000..f370a1ca --- /dev/null +++ b/ui/src/pages/universalDelegator/components/NetworkCard.tsx @@ -0,0 +1,88 @@ +import type { MouseEvent, ReactNode } from "react"; + +import type { NetworkSlot } from "../logic"; +import { SlotIndexBadge } from "./SlotIndexBadge"; +import { SlotBalances, SlotFill } from "./SlotVisuals"; + +type NetworkCardProps = { + network: NetworkSlot; + networkIndex?: bigint; + allocatedPct: number; + pendingPct: number; + allocatedDisplay: string; + pendingDisplay: string; + isShared: boolean; + isFocused: boolean; + isHovered: boolean; + zoomable: boolean; + networkGrow: number; + networkWidthPct: number; + sizeInvalid: boolean; + subnetworkInvalid: boolean; + onCopyIndex: (index: bigint) => void; + onSubnetworkChange: (value: string) => void; + onSizeChange: (value: string) => void; + onCardClick: (event: MouseEvent) => void; + onCardHover: (event: MouseEvent) => void; + onCardLeave: () => void; + children: ReactNode; +}; + +export function NetworkCard(props: NetworkCardProps) { + const draft = props.network.state.draft; + const baseClass = props.isShared + ? "card bg-base-200 border shadow relative overflow-hidden transition-colors" + : "card shrink-0 min-w-[18rem] bg-base-200 border shadow relative overflow-hidden transition-colors"; + const borderClass = props.zoomable ? (props.isHovered ? "border-white" : "border-base-300") : "border-base-300"; + const cursorClass = props.zoomable ? (props.isFocused ? "cursor-zoom-out" : "cursor-zoom-in") : ""; + + return ( +
+ +
+
+
+
+ {props.networkIndex !== undefined ? ( + + ) : null} +
Network
+
+ + props.onSubnetworkChange(e.target.value)} + /> +
+ + +
+ + {props.children} +
+
+ ); +} diff --git a/ui/src/pages/universalDelegator/components/OperatorCard.tsx b/ui/src/pages/universalDelegator/components/OperatorCard.tsx new file mode 100644 index 00000000..a55a61bb --- /dev/null +++ b/ui/src/pages/universalDelegator/components/OperatorCard.tsx @@ -0,0 +1,67 @@ +import type { OperatorSlot } from "../logic"; +import { SlotIndexBadge } from "./SlotIndexBadge"; +import { SlotBalances, SlotFill } from "./SlotVisuals"; + +type OperatorCardProps = { + operator: OperatorSlot; + operatorIndex?: bigint; + allocatedPct: number; + pendingPct: number; + allocatedDisplay: string; + pendingDisplay: string; + operatorGrow: number; + sizeInvalid: boolean; + operatorInvalid: boolean; + onCopyIndex: (index: bigint) => void; + onOperatorChange: (value: string) => void; + onSizeChange: (value: string) => void; +}; + +export function OperatorCard(props: OperatorCardProps) { + const draft = props.operator.state.draft; + + return ( +
+ +
+
+
+
+ {props.operatorIndex !== undefined ? ( + + ) : null} +
Operator
+
+ + props.onOperatorChange(e.target.value)} + /> +
+ + +
+
+
+ ); +} diff --git a/ui/src/pages/universalDelegator/components/SlotIndexBadge.tsx b/ui/src/pages/universalDelegator/components/SlotIndexBadge.tsx new file mode 100644 index 00000000..dd5d8ae5 --- /dev/null +++ b/ui/src/pages/universalDelegator/components/SlotIndexBadge.tsx @@ -0,0 +1,14 @@ +import { formatIndex, getChildIndex } from "../../../utils/universalDelegatorIndex"; + +export function SlotIndexBadge(props: { index: bigint; onCopy: (index: bigint) => void }) { + return ( + + ); +} diff --git a/ui/src/pages/universalDelegator/components/SlotVisuals.tsx b/ui/src/pages/universalDelegator/components/SlotVisuals.tsx new file mode 100644 index 00000000..0d68585f --- /dev/null +++ b/ui/src/pages/universalDelegator/components/SlotVisuals.tsx @@ -0,0 +1,74 @@ +import { forwardRef, type CSSProperties } from "react"; + +const FILL_OPACITY = 0.2; + +function pendingPatternStyle(colorVar: string): CSSProperties { + const lineColor = `var(${colorVar})`; + return { + backgroundImage: `linear-gradient(${lineColor} 0 2px, transparent 2px 10px), linear-gradient(90deg, ${lineColor} 0 2px, transparent 2px 10px)`, + backgroundSize: "10px 10px", + backgroundPosition: "-1px -1px", + backgroundRepeat: "repeat", + opacity: FILL_OPACITY, + }; +} + +function allocatedFillStyle(colorVar: string): CSSProperties { + return { backgroundColor: `var(${colorVar})`, opacity: FILL_OPACITY }; +} + +export function SlotFill(props: { allocatedPct: number; pendingPct: number; colorVar: string }) { + return ( + <> +
+ {props.pendingPct > 0 ? ( +
+ ) : null} + + ); +} + +export function SlotBalances(props: { allocated: string; pending: string }) { + return ( +
+
Allocated: {props.allocated}
+
Pending: {props.pending}
+
+ ); +} + +type AddSlotButtonProps = { + label: string; + className: string; + onClick: () => void; + dataNoZoom?: boolean; +}; + +export const AddSlotButton = forwardRef((props, ref) => { + return ( + + ); +}); + +AddSlotButton.displayName = "AddSlotButton"; diff --git a/ui/src/pages/universalDelegator/components/StatusBanner.tsx b/ui/src/pages/universalDelegator/components/StatusBanner.tsx new file mode 100644 index 00000000..415cc1b2 --- /dev/null +++ b/ui/src/pages/universalDelegator/components/StatusBanner.tsx @@ -0,0 +1,12 @@ +type StatusBannerProps = { + tone: "info" | "success" | "warning" | "error"; + message: string; +}; + +export function StatusBanner(props: StatusBannerProps) { + return ( +
+ {props.message} +
+ ); +} diff --git a/ui/src/pages/universalDelegator/components/WalletStatus.tsx b/ui/src/pages/universalDelegator/components/WalletStatus.tsx new file mode 100644 index 00000000..e6e51675 --- /dev/null +++ b/ui/src/pages/universalDelegator/components/WalletStatus.tsx @@ -0,0 +1,40 @@ +type WalletStatusProps = { + authenticated: boolean; + walletConnected: boolean; + shortAccountAddress: string; + accountAddress?: string | null; + chainLabel: string; + actionClass: string; + onLogin: () => void; + onLogout: () => void; +}; + +export function WalletStatus(props: WalletStatusProps) { + return ( +
+
+
+ + {props.walletConnected ? "Wallet connected" : "Wallet disconnected"} +
+ {props.walletConnected ? ( +
+ + {props.shortAccountAddress} + + {props.chainLabel} +
+ ) : null} +
+ {props.authenticated ? ( + + ) : ( + + )} +
+ ); +} diff --git a/ui/src/pages/universalDelegator/useTxStatus.ts b/ui/src/pages/universalDelegator/useTxStatus.ts new file mode 100644 index 00000000..7a0e04b4 --- /dev/null +++ b/ui/src/pages/universalDelegator/useTxStatus.ts @@ -0,0 +1,38 @@ +import { useMemo } from "react"; + +export type TxStatus = { + state: "idle" | "pending" | "confirming" | "success" | "error"; + show: boolean; + message: string; + tone: "info" | "success" | "error"; +}; + +type TxStatusParams = { + isPending: boolean; + isConfirming: boolean; + isConfirmed: boolean; + error?: { message?: string } | null; +}; + +export function useTxStatus(params: TxStatusParams): TxStatus { + return useMemo(() => { + if (params.error) { + return { + state: "error", + show: true, + message: params.error.message ?? "Transaction failed.", + tone: "error", + }; + } + if (params.isConfirmed) { + return { state: "success", show: true, message: "Confirmed", tone: "success" }; + } + if (params.isConfirming) { + return { state: "confirming", show: true, message: "Waiting for confirmation...", tone: "info" }; + } + if (params.isPending) { + return { state: "pending", show: true, message: "Waiting for wallet approval...", tone: "info" }; + } + return { state: "idle", show: false, message: "", tone: "info" }; + }, [params.error, params.isConfirmed, params.isConfirming, params.isPending]); +} From 02426347128b5ec264742bb95033cc1829635278 Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 29 Dec 2025 00:07:47 +0400 Subject: [PATCH 07/10] test: more details to spec & more tests --- spec/delegator/UniversalDelegator.md | 12 ++ test/delegator/UniversalDelegator.t.sol | 194 ++++++++++++++++++++++++ 2 files changed, 206 insertions(+) diff --git a/spec/delegator/UniversalDelegator.md b/spec/delegator/UniversalDelegator.md index ef72efa9..09c63837 100644 --- a/spec/delegator/UniversalDelegator.md +++ b/spec/delegator/UniversalDelegator.md @@ -178,6 +178,18 @@ Operator assignment is tracked historically via `operatorToSlot[parentIndex][ope With the enforced depth policy, this means “restaked” is effectively “the operator’s network slot (depth 2) is under a shared group slot (depth 1)”. +## Shared groups: intent and trade-offs + +Shared groups (depth 1 with `isShared = true`) are intended to model restaking between sibling networks: + +- Depth-2 network slots allocate against the same parent availability, so their allocations can overlap. +- Operators remain isolated within each network (depth 3 is never shared). + +Trade-offs of shared groups: + +- Slashes across subnetworks compete for the same underlying vault stake; slash ordering (including captureTimestamp choice within an epoch) can affect remaining slashable stake for other subnetworks. +- There is no per-network reserve or fairness isolation inside a shared group; use isolated groups for strict separation. + ## Hints Some `*At(...)` view functions accept `bytes hints` to speed up checkpoint lookups. diff --git a/test/delegator/UniversalDelegator.t.sol b/test/delegator/UniversalDelegator.t.sol index e3c1c4bc..b1e1da28 100644 --- a/test/delegator/UniversalDelegator.t.sol +++ b/test/delegator/UniversalDelegator.t.sol @@ -26,6 +26,7 @@ contract UniversalDelegatorTest is Test { using UniversalDelegatorIndex for uint96; uint48 internal constant EPOCH_DURATION = 3; + uint256 internal constant MAX_AMOUNT = 1_000_000 ether; address internal owner; address internal alice; @@ -358,6 +359,199 @@ contract UniversalDelegatorTest is Test { assertEq(delegator.getAllocated(op2), 30); } + function test_isolatedGroups_prioritizedOverTime() public { + delegator.createSlot(0, false, 30); + delegator.createSlot(0, false, 50); + delegator.createSlot(0, false, 100); + + uint96 slot1 = uint96(0).createIndex(uint32(1)); + uint96 slot2 = uint96(0).createIndex(uint32(2)); + uint96 slot3 = uint96(0).createIndex(uint32(3)); + + vm.warp(1); + _deposit(alice, 60); + + assertEq(delegator.getAllocatedAt(slot1, 1, ""), 30); + assertEq(delegator.getAllocatedAt(slot2, 1, ""), 30); + assertEq(delegator.getAllocatedAt(slot3, 1, ""), 0); + + vm.warp(2); + _deposit(alice, 60); + + assertEq(delegator.getAllocatedAt(slot1, 2, ""), 30); + assertEq(delegator.getAllocatedAt(slot2, 2, ""), 50); + assertEq(delegator.getAllocatedAt(slot3, 2, ""), 40); + } + + function test_isolatedNetworks_followGroupPriority() public { + _deposit(alice, 150); + + delegator.createSlot(0, false, 200); + uint96 group = uint96(0).createIndex(uint32(1)); + + delegator.createSlot(group, false, 60); + delegator.createSlot(group, false, 120); + uint96 net1 = group.createIndex(uint32(1)); + uint96 net2 = group.createIndex(uint32(2)); + + assertEq(delegator.getAllocated(group), 150); + assertEq(delegator.getAllocated(net1), 60); + assertEq(delegator.getAllocated(net2), 90); + } + + function test_isolatedOperators_prioritizedAfterStakeDecrease() public { + delegator.createSlot(0, false, 1_000); + uint96 group = uint96(0).createIndex(uint32(1)); + + delegator.createSlot(group, false, 1_000); + uint96 networkSlot = group.createIndex(uint32(1)); + + delegator.createSlot(networkSlot, false, 70); + delegator.createSlot(networkSlot, false, 70); + uint96 op1 = networkSlot.createIndex(uint32(1)); + uint96 op2 = networkSlot.createIndex(uint32(2)); + + vm.warp(1); + _deposit(alice, 100); + + assertEq(delegator.getAllocated(op1), 70); + assertEq(delegator.getAllocated(op2), 30); + + vm.warp(2); + _withdraw(alice, 40); + + assertEq(delegator.getAllocated(op1), 60); + assertEq(delegator.getAllocated(op2), 0); + } + + function test_isolatedSlots_pendingFree_delaysReallocation() public { + _deposit(alice, 100); + + delegator.createSlot(0, false, 70); + delegator.createSlot(0, false, 70); + uint96 slot1 = uint96(0).createIndex(uint32(1)); + uint96 slot2 = uint96(0).createIndex(uint32(2)); + + assertEq(delegator.getAllocated(slot1), 70); + assertEq(delegator.getAllocated(slot2), 30); + + vm.warp(1); + delegator.setSize(slot1, 30); + + assertEq(delegator.getAvailable(0), 60); + assertEq(delegator.getAllocated(slot1), 30); + assertEq(delegator.getAllocated(slot2), 30); + + vm.warp(1 + EPOCH_DURATION); + assertEq(delegator.getAvailable(0), 100); + assertEq(delegator.getAllocated(slot1), 30); + assertEq(delegator.getAllocated(slot2), 70); + } + + function test_isolatedSlots_lateSizeIncrease_doesNotAffectEarlier() public { + _deposit(alice, 90); + + delegator.createSlot(0, false, 50); + delegator.createSlot(0, false, 60); + uint96 slot1 = uint96(0).createIndex(uint32(1)); + uint96 slot2 = uint96(0).createIndex(uint32(2)); + + assertEq(delegator.getAllocated(slot1), 50); + assertEq(delegator.getAllocated(slot2), 40); + + vm.warp(1); + delegator.setSize(slot2, 100); + + assertEq(delegator.getAllocated(slot1), 50); + assertEq(delegator.getAllocated(slot2), 40); + + vm.warp(2); + _deposit(alice, 30); + + assertEq(delegator.getAllocated(slot1), 50); + assertEq(delegator.getAllocated(slot2), 70); + } + + function testFuzz_isolatedGroups_followPriority(uint256 depositAmount, uint256 size1, uint256 size2) public { + uint256 amount = bound(depositAmount, 1, MAX_AMOUNT); + uint256 cap1 = bound(size1, 0, MAX_AMOUNT); + uint256 cap2 = bound(size2, 0, MAX_AMOUNT); + + delegator.createSlot(0, false, cap1); + delegator.createSlot(0, false, cap2); + uint96 slot1 = uint96(0).createIndex(uint32(1)); + uint96 slot2 = uint96(0).createIndex(uint32(2)); + + _deposit(alice, amount); + + uint256 expected1 = amount < cap1 ? amount : cap1; + uint256 remaining = amount > expected1 ? amount - expected1 : 0; + uint256 expected2 = remaining < cap2 ? remaining : cap2; + + assertEq(delegator.getAllocated(slot1), expected1); + assertEq(delegator.getAllocated(slot2), expected2); + assertLe(delegator.getAllocated(slot1) + delegator.getAllocated(slot2), delegator.getAvailable(0)); + } + + function testFuzz_isolatedOperators_followPriority(uint256 depositAmount, uint256 size1, uint256 size2) public { + uint256 amount = bound(depositAmount, 1, MAX_AMOUNT); + uint256 cap1 = bound(size1, 0, MAX_AMOUNT); + uint256 cap2 = bound(size2, 0, MAX_AMOUNT); + + delegator.createSlot(0, false, MAX_AMOUNT); + uint96 group = uint96(0).createIndex(uint32(1)); + + delegator.createSlot(group, false, MAX_AMOUNT); + uint96 networkSlot = group.createIndex(uint32(1)); + + delegator.createSlot(networkSlot, false, cap1); + delegator.createSlot(networkSlot, false, cap2); + uint96 op1 = networkSlot.createIndex(uint32(1)); + uint96 op2 = networkSlot.createIndex(uint32(2)); + + _deposit(alice, amount); + + uint256 expected1 = amount < cap1 ? amount : cap1; + uint256 remaining = amount > expected1 ? amount - expected1 : 0; + uint256 expected2 = remaining < cap2 ? remaining : cap2; + + assertEq(delegator.getAllocated(op1), expected1); + assertEq(delegator.getAllocated(op2), expected2); + } + + function testFuzz_isolatedSlots_depositWithdraw_overTime( + uint256 depositAmount, + uint256 withdrawAmount, + uint256 size1, + uint256 size2 + ) public { + uint256 amount = bound(depositAmount, 1, MAX_AMOUNT); + uint256 cap1 = bound(size1, 0, MAX_AMOUNT); + uint256 cap2 = bound(size2, 0, MAX_AMOUNT); + + delegator.createSlot(0, false, cap1); + delegator.createSlot(0, false, cap2); + uint96 slot1 = uint96(0).createIndex(uint32(1)); + uint96 slot2 = uint96(0).createIndex(uint32(2)); + + vm.warp(1); + _deposit(alice, amount); + + uint256 withdraw = bound(withdrawAmount, 0, amount); + vm.warp(2); + if (withdraw > 0) { + _withdraw(alice, withdraw); + } + + uint256 remaining = amount - withdraw; + uint256 expected1 = remaining < cap1 ? remaining : cap1; + uint256 afterFirst = remaining > expected1 ? remaining - expected1 : 0; + uint256 expected2 = afterFirst < cap2 ? afterFirst : cap2; + + assertEq(delegator.getAllocated(slot1), expected1); + assertEq(delegator.getAllocated(slot2), expected2); + } + function test_isRestaked_trueWhenGroupIsShared() public { bytes32 subnetwork = bytes32(uint256(1)); From 6843140ca6d60ba0ec18be78977907af56927f84 Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 30 Dec 2025 02:01:11 +0400 Subject: [PATCH 08/10] fix: fully isolated groups --- spec/delegator/UniversalDelegator.md | 6 +- src/contracts/delegator/BaseDelegator.sol | 6 + .../delegator/UniversalDelegator.sol | 84 ++++-- test/delegator/UniversalDelegator.t.sol | 241 +++++++++++++++++- ui/src/pages/universalDelegator/logic.ts | 39 ++- 5 files changed, 321 insertions(+), 55 deletions(-) diff --git a/spec/delegator/UniversalDelegator.md b/spec/delegator/UniversalDelegator.md index 09c63837..fce1143b 100644 --- a/spec/delegator/UniversalDelegator.md +++ b/spec/delegator/UniversalDelegator.md @@ -44,7 +44,7 @@ Practical implications: Each slot stores (all checkpointed unless stated): - `size`: per-slot cap (upper bound on allocation from its parent). -- `prevSum`: prefix sum of *sizes* of earlier siblings (used only when the parent is not shared). +- `prevSum`: prefix sum of _sizes_ of earlier siblings (used only when the parent is not shared). - `isShared`: if `1`, this slot’s **children** can overlap their allocation (restaking between siblings). - `pendingFreeCumulative`: cumulative “pending free” amount used to delay re-use of freed stake. - `children[]`: ordered list of `uint32 localIndex` values. @@ -150,11 +150,11 @@ Rules: - Reverts if not assigned (`NetworkNotAssigned()`). - Reverts if the slot still has allocation (`SlotAllocated()`). -The active slot for a subnetwork is stored historically via `networkToSlot[subnetwork]` checkpoints. +The active slot for a subnetwork is stored historically via `_networkToSlot[subnetwork]` checkpoints. ### Operators -Operators are assigned *under a specific parent slot* (typically the network’s slot) using: +Operators are assigned _under a specific parent slot_ (typically the network’s slot) using: - `assignOperator(index, operator)` diff --git a/src/contracts/delegator/BaseDelegator.sol b/src/contracts/delegator/BaseDelegator.sol index 8493a447..03c821f0 100644 --- a/src/contracts/delegator/BaseDelegator.sol +++ b/src/contracts/delegator/BaseDelegator.sol @@ -181,6 +181,8 @@ abstract contract BaseDelegator is revert NotSlasher(); } + _onSlash(subnetwork, operator, amount, captureTimestamp, data); + address hook_ = hook; if (hook_ != address(0)) { bytes memory calldata_ = @@ -232,5 +234,9 @@ abstract contract BaseDelegator is function _setMaxNetworkLimit(bytes32 subnetwork, uint256 amount) internal virtual {} + function _onSlash(bytes32 subnetwork, address operator, uint256 amount, uint48 captureTimestamp, bytes memory data) + internal + virtual {} + function __initialize(address vault_, bytes memory data) internal virtual returns (BaseParams memory) {} } diff --git a/src/contracts/delegator/UniversalDelegator.sol b/src/contracts/delegator/UniversalDelegator.sol index 3254e733..7f8042c2 100644 --- a/src/contracts/delegator/UniversalDelegator.sol +++ b/src/contracts/delegator/UniversalDelegator.sol @@ -33,9 +33,10 @@ contract UniversalDelegator is BaseDelegator, MulticallUpgradeable, IUniversalDe // @dev index is {32 bytes of child index at depth 1}{32 bytes - depth 2}{32 bytes - depth 3} mapping(uint96 index => Slot slot) public slots; - mapping(bytes32 subnetwork => Checkpoints.Trace208) public networkToSlot; - mapping(uint96 parentIndex => mapping(address operator => Checkpoints.Trace208)) public operatorToSlot; + mapping(bytes32 subnetwork => Checkpoints.Trace208) internal _networkToSlot; + mapping(uint96 parentIndex => mapping(address operator => Checkpoints.Trace208)) internal _operatorToSlot; mapping(uint96 index => address operator) public operatorBySlot; + mapping(uint96 index => Checkpoints.Trace256 amount) internal _cumulativeSlash; constructor( address networkRegistry, @@ -117,12 +118,12 @@ contract UniversalDelegator is BaseDelegator, MulticallUpgradeable, IUniversalDe view returns (uint256) { - uint96 index = slotByOperatorAt(slotByNetworkAt(subnetwork, timestamp, hints), operator, timestamp, hints); + uint96 index = slotOfAt(subnetwork, operator, timestamp, hints); return index > 0 ? getAllocatedAt(index, timestamp, hints) : 0; } function getAllocated(bytes32 subnetwork, address operator) public view returns (uint256) { - uint96 index = slotByOperator(slotByNetwork(subnetwork), operator); + uint96 index = slotOf(subnetwork, operator); return index > 0 ? getAllocated(index) : 0; } @@ -131,24 +132,36 @@ contract UniversalDelegator is BaseDelegator, MulticallUpgradeable, IUniversalDe return getAvailable(index).saturatingSub(_getChildrenSize(index)); } - function slotByNetworkAt(bytes32 subnetwork, uint48 timestamp, bytes memory hint) public view returns (uint96) { - return uint96(networkToSlot[subnetwork].upperLookupRecent(timestamp, hint)); + function slotOfNetworkAt(bytes32 subnetwork, uint48 timestamp, bytes memory hint) public view returns (uint96) { + return uint96(_networkToSlot[subnetwork].upperLookupRecent(timestamp, hint)); } - function slotByNetwork(bytes32 subnetwork) public view returns (uint96) { - return uint96(networkToSlot[subnetwork].latest()); + function slotOfNetwork(bytes32 subnetwork) public view returns (uint96) { + return uint96(_networkToSlot[subnetwork].latest()); } - function slotByOperatorAt(uint96 parentIndex, address operator, uint48 timestamp, bytes memory hint) + function slotOfOperatorAt(uint96 parentIndex, address operator, uint48 timestamp, bytes memory hint) public view returns (uint96) { - return uint96(operatorToSlot[parentIndex][operator].upperLookupRecent(timestamp, hint)); + return uint96(_operatorToSlot[parentIndex][operator].upperLookupRecent(timestamp, hint)); } - function slotByOperator(uint96 parentIndex, address operator) public view returns (uint96) { - return uint96(operatorToSlot[parentIndex][operator].latest()); + function slotOfOperator(uint96 parentIndex, address operator) public view returns (uint96) { + return uint96(_operatorToSlot[parentIndex][operator].latest()); + } + + function slotOfAt(bytes32 subnetwork, address operator, uint48 timestamp, bytes memory hints) + public + view + returns (uint96) + { + return slotOfOperatorAt(slotOfNetworkAt(subnetwork, timestamp, hints), operator, timestamp, hints); + } + + function slotOf(bytes32 subnetwork, address operator) public view returns (uint96) { + return slotOfOperator(slotOfNetwork(subnetwork), operator); } function isRestakedAt(bytes32 subnetwork, address operator, uint48 timestamp, bytes memory hints) @@ -156,7 +169,7 @@ contract UniversalDelegator is BaseDelegator, MulticallUpgradeable, IUniversalDe view returns (bool) { - uint96 index = slotByOperatorAt(slotByNetworkAt(subnetwork, timestamp, hints), operator, timestamp, hints); + uint96 index = slotOfAt(subnetwork, operator, timestamp, hints); if (index == 0) { return false; } @@ -169,7 +182,7 @@ contract UniversalDelegator is BaseDelegator, MulticallUpgradeable, IUniversalDe } function isRestaked(bytes32 subnetwork, address operator) public view returns (bool) { - uint96 index = slotByOperator(slotByNetwork(subnetwork), operator); + uint96 index = slotOf(subnetwork, operator); if (index == 0) { return false; } @@ -276,23 +289,23 @@ contract UniversalDelegator is BaseDelegator, MulticallUpgradeable, IUniversalDe if (index.getDepth() != 2) { revert WrongDepth(); } - if (slotByNetwork(subnetwork) > 0) { + if (slotOfNetwork(subnetwork) > 0) { revert NetworkAlreadyAssigned(); } - networkToSlot[subnetwork].push(uint48(block.timestamp), index); + _networkToSlot[subnetwork].push(uint48(block.timestamp), index); emit AssignNetwork(index, subnetwork); } function unassignNetwork(bytes32 subnetwork) public onlyRole(CURATOR_ROLE) { - uint96 index = slotByNetwork(subnetwork); + uint96 index = slotOfNetwork(subnetwork); if (index == 0) { revert NetworkNotAssigned(); } if (getAllocated(index) > 0) { revert SlotAllocated(); } - networkToSlot[subnetwork].push(uint48(block.timestamp), 0); + _networkToSlot[subnetwork].push(uint48(block.timestamp), 0); emit UnassignNetwork(subnetwork); } @@ -302,24 +315,24 @@ contract UniversalDelegator is BaseDelegator, MulticallUpgradeable, IUniversalDe revert WrongDepth(); } uint96 parentIndex = index.getParentIndex(); - if (slotByOperator(parentIndex, operator) != 0) { + if (slotOfOperator(parentIndex, operator) != 0) { revert OperatorAlreadyAssigned(); } - operatorToSlot[parentIndex][operator].push(uint48(block.timestamp), index); + _operatorToSlot[parentIndex][operator].push(uint48(block.timestamp), index); operatorBySlot[index] = operator; emit AssignOperator(index, operator); } function unassignOperator(uint96 parentIndex, address operator) public onlyRole(CURATOR_ROLE) { - uint96 index = slotByOperator(parentIndex, operator); + uint96 index = slotOfOperator(parentIndex, operator); if (index == 0) { revert OperatorNotAssigned(); } if (getAllocated(index) > 0) { revert SlotAllocated(); } - operatorToSlot[parentIndex][operator].push(uint48(block.timestamp), 0); + _operatorToSlot[parentIndex][operator].push(uint48(block.timestamp), 0); delete operatorBySlot[index]; emit UnassignOperator(index, operator); @@ -366,6 +379,33 @@ contract UniversalDelegator is BaseDelegator, MulticallUpgradeable, IUniversalDe function _setMaxNetworkLimit(bytes32 subnetwork, uint256 amount) internal override {} + function _onSlash( + bytes32 subnetwork, + address operator, + uint256 amount, + uint48 captureTimestamp, + bytes memory /*data*/ + ) + internal + override + { + uint96 groupIndex = + slotOfAt(subnetwork, operator, captureTimestamp, new bytes(0)).getParentIndex().getParentIndex(); + + uint256 latestCumulativeSlash = _cumulativeSlash[groupIndex].latest(); + if ( + amount + > getAllocatedAt(groupIndex, captureTimestamp, new bytes(0)) + .saturatingSub( + latestCumulativeSlash - _cumulativeSlash[groupIndex].upperLookupRecent(captureTimestamp) + ) + ) { + revert(); + } + + _cumulativeSlash[groupIndex].push(uint48(block.timestamp), latestCumulativeSlash + amount); + } + function __initialize(address, bytes memory data) internal override returns (IBaseDelegator.BaseParams memory) { InitParams memory params = abi.decode(data, (InitParams)); diff --git a/test/delegator/UniversalDelegator.t.sol b/test/delegator/UniversalDelegator.t.sol index b1e1da28..4888d32a 100644 --- a/test/delegator/UniversalDelegator.t.sol +++ b/test/delegator/UniversalDelegator.t.sol @@ -8,15 +8,23 @@ import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol" import {VaultFactory} from "../../src/contracts/VaultFactory.sol"; import {DelegatorFactory} from "../../src/contracts/DelegatorFactory.sol"; import {SlasherFactory} from "../../src/contracts/SlasherFactory.sol"; +import {NetworkRegistry} from "../../src/contracts/NetworkRegistry.sol"; +import {OperatorRegistry} from "../../src/contracts/OperatorRegistry.sol"; import {VaultConfigurator} from "../../src/contracts/VaultConfigurator.sol"; +import {NetworkMiddlewareService} from "../../src/contracts/service/NetworkMiddlewareService.sol"; +import {OptInService} from "../../src/contracts/service/OptInService.sol"; import {Vault} from "../../src/contracts/vault/Vault.sol"; import {UniversalDelegator} from "../../src/contracts/delegator/UniversalDelegator.sol"; +import {Slasher} from "../../src/contracts/slasher/Slasher.sol"; import {UniversalDelegatorIndex} from "../../src/contracts/libraries/UniversalDelegatorIndex.sol"; +import {Subnetwork} from "../../src/contracts/libraries/Subnetwork.sol"; import {IBaseDelegator} from "../../src/interfaces/delegator/IBaseDelegator.sol"; import {IUniversalDelegator} from "../../src/interfaces/delegator/IUniversalDelegator.sol"; +import {ISlasher} from "../../src/interfaces/slasher/ISlasher.sol"; +import {IBaseSlasher} from "../../src/interfaces/slasher/IBaseSlasher.sol"; import {IVault} from "../../src/interfaces/vault/IVault.sol"; import {IVaultConfigurator} from "../../src/interfaces/IVaultConfigurator.sol"; @@ -24,6 +32,7 @@ import {Token} from "../mocks/Token.sol"; contract UniversalDelegatorTest is Test { using UniversalDelegatorIndex for uint96; + using Subnetwork for address; uint48 internal constant EPOCH_DURATION = 3; uint256 internal constant MAX_AMOUNT = 1_000_000 ether; @@ -35,11 +44,17 @@ contract UniversalDelegatorTest is Test { VaultFactory internal vaultFactory; DelegatorFactory internal delegatorFactory; SlasherFactory internal slasherFactory; + NetworkRegistry internal networkRegistry; + OperatorRegistry internal operatorRegistry; + NetworkMiddlewareService internal networkMiddlewareService; + OptInService internal operatorVaultOptInService; + OptInService internal operatorNetworkOptInService; VaultConfigurator internal vaultConfigurator; Token internal collateral; Vault internal vault; UniversalDelegator internal delegator; + Slasher internal slasher; function setUp() public { vm.warp(0); @@ -51,6 +66,13 @@ contract UniversalDelegatorTest is Test { vaultFactory = new VaultFactory(owner); delegatorFactory = new DelegatorFactory(owner); slasherFactory = new SlasherFactory(owner); + networkRegistry = new NetworkRegistry(); + operatorRegistry = new OperatorRegistry(); + networkMiddlewareService = new NetworkMiddlewareService(address(networkRegistry)); + operatorVaultOptInService = + new OptInService(address(operatorRegistry), address(vaultFactory), "OperatorVaultOptInService"); + operatorNetworkOptInService = + new OptInService(address(operatorRegistry), address(networkRegistry), "OperatorNetworkOptInService"); address vaultImpl = address(new Vault(address(delegatorFactory), address(slasherFactory), address(vaultFactory))); @@ -58,21 +80,31 @@ contract UniversalDelegatorTest is Test { address delegatorImpl = address( new UniversalDelegator( - address(0x1111), + address(networkRegistry), address(vaultFactory), - address(0x2222), - address(0x3333), + address(operatorVaultOptInService), + address(operatorNetworkOptInService), address(delegatorFactory), delegatorFactory.totalTypes() ) ); delegatorFactory.whitelist(delegatorImpl); + address slasherImpl = address( + new Slasher( + address(vaultFactory), + address(networkMiddlewareService), + address(slasherFactory), + slasherFactory.totalTypes() + ) + ); + slasherFactory.whitelist(slasherImpl); + collateral = new Token("Token"); vaultConfigurator = new VaultConfigurator(address(vaultFactory), address(delegatorFactory), address(slasherFactory)); - (address vault_, address delegator_,) = vaultConfigurator.create( + (address vault_, address delegator_, address slasher_) = vaultConfigurator.create( IVaultConfigurator.InitParams({ version: vaultFactory.lastVersion(), owner: owner, @@ -100,14 +132,17 @@ contract UniversalDelegatorTest is Test { curatorRoleHolder: owner }) ), - withSlasher: false, + withSlasher: true, slasherIndex: 0, - slasherParams: "" + slasherParams: abi.encode( + ISlasher.InitParams({baseParams: IBaseSlasher.BaseParams({isBurnerHook: false})}) + ) }) ); vault = Vault(vault_); delegator = UniversalDelegator(delegator_); + slasher = Slasher(slasher_); } function test_checkpointTracksHistory_andDefaults() public { @@ -400,10 +435,10 @@ contract UniversalDelegatorTest is Test { } function test_isolatedOperators_prioritizedAfterStakeDecrease() public { - delegator.createSlot(0, false, 1_000); + delegator.createSlot(0, false, 1000); uint96 group = uint96(0).createIndex(uint32(1)); - delegator.createSlot(group, false, 1_000); + delegator.createSlot(group, false, 1000); uint96 networkSlot = group.createIndex(uint32(1)); delegator.createSlot(networkSlot, false, 70); @@ -472,6 +507,172 @@ contract UniversalDelegatorTest is Test { assertEq(delegator.getAllocated(slot2), 70); } + function test_sharedGroup_slashCappedAcrossNetworks_sameCaptureTimestamp() public { + address network1 = makeAddr("network1"); + address network2 = makeAddr("network2"); + address network3 = makeAddr("network3"); + address middleware = makeAddr("middleware"); + address operator1 = alice; + address operator2 = bob; + address operator3 = makeAddr("charlie"); + + _registerNetwork(network1, middleware); + _registerNetwork(network2, middleware); + _registerNetwork(network3, middleware); + _registerOperator(operator1); + _registerOperator(operator2); + _registerOperator(operator3); + _optIn(operator1, network1); + _optIn(operator2, network2); + _optIn(operator3, network3); + + bytes32 subnetwork1 = network1.subnetwork(0); + bytes32 subnetwork2 = network2.subnetwork(0); + bytes32 subnetwork3 = network3.subnetwork(0); + + delegator.createSlot(0, true, 60); + delegator.createSlot(0, false, 40); + uint96 group1 = uint96(0).createIndex(uint32(1)); + uint96 group2 = uint96(0).createIndex(uint32(2)); + + delegator.createSlot(group1, false, 60); + delegator.createSlot(group1, false, 60); + uint96 netSlot1 = group1.createIndex(uint32(1)); + uint96 netSlot2 = group1.createIndex(uint32(2)); + delegator.assignNetwork(netSlot1, subnetwork1); + delegator.assignNetwork(netSlot2, subnetwork2); + + delegator.createSlot(netSlot1, false, 60); + uint96 opSlot1 = netSlot1.createIndex(uint32(1)); + delegator.assignOperator(opSlot1, operator1); + + delegator.createSlot(netSlot2, false, 60); + uint96 opSlot2 = netSlot2.createIndex(uint32(1)); + delegator.assignOperator(opSlot2, operator2); + + delegator.createSlot(group2, false, 40); + uint96 netSlot3 = group2.createIndex(uint32(1)); + delegator.assignNetwork(netSlot3, subnetwork3); + + delegator.createSlot(netSlot3, false, 40); + uint96 opSlot3 = netSlot3.createIndex(uint32(1)); + delegator.assignOperator(opSlot3, operator3); + + vm.warp(18); + _deposit(alice, 100); + + uint48 captureTimestamp = 18; + vm.warp(20); + + vm.startPrank(middleware); + assertEq(slasher.slash(subnetwork1, operator1, 60, captureTimestamp, ""), 60); + vm.expectRevert(); + slasher.slash(subnetwork2, operator2, 60, captureTimestamp, ""); + assertEq(slasher.slash(subnetwork3, operator3, 40, captureTimestamp, ""), 40); + vm.stopPrank(); + } + + function test_sharedGroup_slashCappedAcrossNetworks_differentCaptureTimestamp() public { + address network1 = makeAddr("network1"); + address network2 = makeAddr("network2"); + address middleware = makeAddr("middleware"); + address operator1 = alice; + address operator2 = bob; + + _registerNetwork(network1, middleware); + _registerNetwork(network2, middleware); + _registerOperator(operator1); + _registerOperator(operator2); + _optIn(operator1, network1); + _optIn(operator2, network2); + + bytes32 subnetwork1 = network1.subnetwork(0); + bytes32 subnetwork2 = network2.subnetwork(0); + + delegator.createSlot(0, true, 60); + uint96 group = uint96(0).createIndex(uint32(1)); + + delegator.createSlot(group, false, 60); + delegator.createSlot(group, false, 60); + uint96 netSlot1 = group.createIndex(uint32(1)); + uint96 netSlot2 = group.createIndex(uint32(2)); + delegator.assignNetwork(netSlot1, subnetwork1); + delegator.assignNetwork(netSlot2, subnetwork2); + + delegator.createSlot(netSlot1, false, 60); + uint96 opSlot1 = netSlot1.createIndex(uint32(1)); + delegator.assignOperator(opSlot1, operator1); + + delegator.createSlot(netSlot2, false, 60); + uint96 opSlot2 = netSlot2.createIndex(uint32(1)); + delegator.assignOperator(opSlot2, operator2); + + vm.warp(1); + _deposit(alice, 60); + + vm.warp(5); + + vm.startPrank(middleware); + assertEq(slasher.slash(subnetwork1, operator1, 60, 3, ""), 60); + vm.expectRevert(); + slasher.slash(subnetwork2, operator2, 60, 4, ""); + vm.stopPrank(); + } + + function test_sharedGroup_slashAllowsNewStake_laterCaptureTimestamp() public { + address network1 = makeAddr("network1"); + address network2 = makeAddr("network2"); + address middleware = makeAddr("middleware"); + address operator1 = alice; + address operator2 = bob; + + _registerNetwork(network1, middleware); + _registerNetwork(network2, middleware); + _registerOperator(operator1); + _registerOperator(operator2); + _optIn(operator1, network1); + _optIn(operator2, network2); + + bytes32 subnetwork1 = network1.subnetwork(0); + bytes32 subnetwork2 = network2.subnetwork(0); + + delegator.createSlot(0, true, 200); + uint96 group = uint96(0).createIndex(uint32(1)); + + delegator.createSlot(group, false, 200); + delegator.createSlot(group, false, 200); + uint96 netSlot1 = group.createIndex(uint32(1)); + uint96 netSlot2 = group.createIndex(uint32(2)); + delegator.assignNetwork(netSlot1, subnetwork1); + delegator.assignNetwork(netSlot2, subnetwork2); + + delegator.createSlot(netSlot1, false, 200); + uint96 opSlot1 = netSlot1.createIndex(uint32(1)); + delegator.assignOperator(opSlot1, operator1); + + delegator.createSlot(netSlot2, false, 200); + uint96 opSlot2 = netSlot2.createIndex(uint32(1)); + delegator.assignOperator(opSlot2, operator2); + + vm.warp(1); + _deposit(alice, 100); + + vm.warp(4); + vm.startPrank(middleware); + assertEq(slasher.slash(subnetwork1, operator1, 60, 2, ""), 60); + vm.expectRevert(); + slasher.slash(subnetwork2, operator2, 60, 2, ""); + vm.stopPrank(); + + vm.warp(6); + _deposit(alice, 80); + + vm.warp(8); + vm.startPrank(middleware); + assertEq(slasher.slash(subnetwork2, operator2, 60, 6, ""), 60); + vm.stopPrank(); + } + function testFuzz_isolatedGroups_followPriority(uint256 depositAmount, uint256 size1, uint256 size2) public { uint256 amount = bound(depositAmount, 1, MAX_AMOUNT); uint256 cap1 = bound(size1, 0, MAX_AMOUNT); @@ -709,7 +910,7 @@ contract UniversalDelegatorTest is Test { _withdraw(alice, 100); delegator.unassignNetwork(subnetwork); - assertEq(delegator.slotByNetwork(subnetwork), 0); + assertEq(delegator.slotOfNetwork(subnetwork), 0); } function test_operatorAssignment_duplicateAndUnassignChecks() public { @@ -739,7 +940,7 @@ contract UniversalDelegatorTest is Test { _withdraw(alice, 100); delegator.unassignOperator(networkSlot, alice); - assertEq(delegator.slotByOperator(networkSlot, alice), 0); + assertEq(delegator.slotOfOperator(networkSlot, alice), 0); } function test_setIsShared_revertsWhenAllocated() public { @@ -857,6 +1058,26 @@ contract UniversalDelegatorTest is Test { assertEq(delegator.getAvailableAt(0, 4, ""), 100); } + function _registerOperator(address operator) internal { + vm.startPrank(operator); + operatorRegistry.registerOperator(); + vm.stopPrank(); + } + + function _registerNetwork(address network, address middleware) internal { + vm.startPrank(network); + networkRegistry.registerNetwork(); + networkMiddlewareService.setMiddleware(middleware); + vm.stopPrank(); + } + + function _optIn(address operator, address network) internal { + vm.startPrank(operator); + operatorVaultOptInService.optIn(address(vault)); + operatorNetworkOptInService.optIn(network); + vm.stopPrank(); + } + function _deposit(address user, uint256 amount) internal { collateral.transfer(user, amount); diff --git a/ui/src/pages/universalDelegator/logic.ts b/ui/src/pages/universalDelegator/logic.ts index d71b754a..630a2535 100644 --- a/ui/src/pages/universalDelegator/logic.ts +++ b/ui/src/pages/universalDelegator/logic.ts @@ -345,7 +345,7 @@ function computeSimulatedAllocationsFromStateWithPending( const parentPending = pendingByIndex.get(parentIndex) ?? 0n; const parentAvailable = saturatingSub(parentAllocated, parentPending); const parentSlot = state.slots.get(parentIndex); - const parentIsShared = parentIndex === 0n ? false : (parentSlot?.isShared ?? false); + const parentIsShared = parentIndex === 0n ? false : parentSlot?.isShared ?? false; let prevSum = 0n; for (const child of children) { @@ -441,12 +441,12 @@ export function computePendingByIndexFromOps(params: { } if (op.kind === "assignNetwork") { - state.networkToSlot.set(op.subnetwork.toLowerCase(), op.index); + state._networkToSlot.set(op.subnetwork.toLowerCase(), op.index); continue; } if (op.kind === "unassignNetwork") { - state.networkToSlot.set(op.subnetwork.toLowerCase(), 0n); + state._networkToSlot.set(op.subnetwork.toLowerCase(), 0n); continue; } @@ -503,7 +503,7 @@ export function computeSimulatedAllocationsWithPending(params: { groupPrevSum += groupSize; const groupIsShared = group.state.draft.isShared; - const groupPending = groupIndex !== undefined ? (pendingByIndex.get(groupIndex.toString()) ?? 0n) : 0n; + const groupPending = groupIndex !== undefined ? pendingByIndex.get(groupIndex.toString()) ?? 0n : 0n; const groupAvailable = saturatingSub(groupAllocated, groupPending); let networkPrevSum = 0n; for (const network of group.networks) { @@ -515,7 +515,7 @@ export function computeSimulatedAllocationsWithPending(params: { if (networkIndex !== undefined) allocatedByIndex.set(networkIndex.toString(), networkAllocated); networkPrevSum += networkSize; - const networkPending = networkIndex !== undefined ? (pendingByIndex.get(networkIndex.toString()) ?? 0n) : 0n; + const networkPending = networkIndex !== undefined ? pendingByIndex.get(networkIndex.toString()) ?? 0n : 0n; const networkAvailable = saturatingSub(networkAllocated, networkPending); let operatorPrevSum = 0n; for (const operator of network.operators) { @@ -815,8 +815,7 @@ export function autoSyncAll(model: UniversalDelegatorModel): { model: UniversalD const synced = network.state.synced; const syncedSize = synced ? parseUint(synced.size) : null; const isSizeDirty = synced === null || syncedSize === null || syncedSize !== size; - const isSubnetworkDirty = - subnetworkValid && (synced === null || synced.subnetwork.trim() !== subnetworkTrimmed); + const isSubnetworkDirty = subnetworkValid && (synced === null || synced.subnetwork.trim() !== subnetworkTrimmed); if (synced === null || isSizeDirty || isSubnetworkDirty) { if (network.index === null) { @@ -940,7 +939,7 @@ type SimState = { children: Map; slots: Map; created: Set; - networkToSlot: Map; + _networkToSlot: Map; operatorBySlot: Map; operatorToSlot: Map; nextChildLocalIndex: Map; @@ -1008,7 +1007,7 @@ function cloneSimState(state: SimState): SimState { children: new Map([...state.children.entries()].map(([k, v]) => [k, v.slice()])), slots: new Map([...state.slots.entries()].map(([k, v]) => [k, { ...v }])), created: new Set(state.created), - networkToSlot: new Map(state.networkToSlot), + _networkToSlot: new Map(state._networkToSlot), operatorBySlot: new Map(state.operatorBySlot), operatorToSlot: new Map(state.operatorToSlot), nextChildLocalIndex: new Map(state.nextChildLocalIndex), @@ -1020,7 +1019,7 @@ export function buildSimStateFromModel(model: UniversalDelegatorModel): SimState children: new Map([[0n, []]]), slots: new Map(), created: new Set([0n]), - networkToSlot: new Map(), + _networkToSlot: new Map(), operatorBySlot: new Map(), operatorToSlot: new Map(), nextChildLocalIndex: new Map(), @@ -1052,7 +1051,7 @@ export function buildSimStateFromModel(model: UniversalDelegatorModel): SimState const subnetworkRaw = (networkSynced?.subnetwork ?? network.state.draft.subnetwork).trim(); const subnetworkParsed = subnetworkRaw === "" ? null : parseBytes32(subnetworkRaw); if (subnetworkParsed) { - state.networkToSlot.set(subnetworkParsed.toLowerCase(), networkIndex); + state._networkToSlot.set(subnetworkParsed.toLowerCase(), networkIndex); } for (const operator of network.operators) { @@ -1134,12 +1133,12 @@ export function simulateOpsFromState(initial: SimState, ops: UdOperation[]): Sim } if (op.kind === "assignNetwork") { - state.networkToSlot.set(op.subnetwork.toLowerCase(), op.index); + state._networkToSlot.set(op.subnetwork.toLowerCase(), op.index); continue; } if (op.kind === "unassignNetwork") { - state.networkToSlot.set(op.subnetwork.toLowerCase(), 0n); + state._networkToSlot.set(op.subnetwork.toLowerCase(), 0n); continue; } @@ -1254,12 +1253,12 @@ function compileMinimalOpsFromInitialAndFinal(params: { initial: SimState; final } const allSubnetworks = new Set(); - for (const key of params.initial.networkToSlot.keys()) allSubnetworks.add(key); - for (const key of params.final.networkToSlot.keys()) allSubnetworks.add(key); + for (const key of params.initial._networkToSlot.keys()) allSubnetworks.add(key); + for (const key of params.final._networkToSlot.keys()) allSubnetworks.add(key); const subnetworkKeys = [...allSubnetworks].sort((a, b) => (a < b ? -1 : a > b ? 1 : 0)); for (const subnetwork of subnetworkKeys) { - const initialIndex = params.initial.networkToSlot.get(subnetwork) ?? 0n; - const finalIndex = params.final.networkToSlot.get(subnetwork) ?? 0n; + const initialIndex = params.initial._networkToSlot.get(subnetwork) ?? 0n; + const finalIndex = params.final._networkToSlot.get(subnetwork) ?? 0n; if (initialIndex === finalIndex) continue; if (initialIndex !== 0n) assignOps.push({ kind: "unassignNetwork", subnetwork: subnetwork as Hex }); if (finalIndex !== 0n) assignOps.push({ kind: "assignNetwork", index: finalIndex, subnetwork: subnetwork as Hex }); @@ -1463,7 +1462,7 @@ function computeSimulatedAllocationsFromState(state: SimState, rootBalance: bigi const children = state.children.get(parentIndex) ?? []; const parentAllocated = allocated.get(parentIndex) ?? 0n; const parentSlot = state.slots.get(parentIndex); - const parentIsShared = parentIndex === 0n ? false : (parentSlot?.isShared ?? false); + const parentIsShared = parentIndex === 0n ? false : parentSlot?.isShared ?? false; let prevSum = 0n; for (const child of children) { @@ -1505,8 +1504,8 @@ export function describeNotEnoughAvailable(params: { parentDepth === 0 ? "root" : parentDepth === 1 - ? `Group #${getChildIndex(parentIndex)}` - : `Network #${getChildIndex(parentIndex)}`; + ? `Group #${getChildIndex(parentIndex)}` + : `Network #${getChildIndex(parentIndex)}`; const childLabel = childDepth === 1 ? "Group" : childDepth === 2 ? "Network" : "Operator"; const children = before.children.get(parentIndex) ?? []; From 08de83fc7930e5b7c334f0a62df8cc5064d43f05 Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 30 Dec 2025 11:37:13 +0400 Subject: [PATCH 09/10] refactor: remove redundant const --- src/contracts/delegator/UniversalDelegator.sol | 1 - 1 file changed, 1 deletion(-) diff --git a/src/contracts/delegator/UniversalDelegator.sol b/src/contracts/delegator/UniversalDelegator.sol index 7f8042c2..6f2613ef 100644 --- a/src/contracts/delegator/UniversalDelegator.sol +++ b/src/contracts/delegator/UniversalDelegator.sol @@ -29,7 +29,6 @@ contract UniversalDelegator is BaseDelegator, MulticallUpgradeable, IUniversalDe } bytes32 public constant CURATOR_ROLE = keccak256("CURATOR_ROLE"); - uint256 MAX_DEPTH = 3; // @dev index is {32 bytes of child index at depth 1}{32 bytes - depth 2}{32 bytes - depth 3} mapping(uint96 index => Slot slot) public slots; From 1243ec525d91b666e0fec99d2b298c27588c1173 Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 13 Jan 2026 09:56:02 +0400 Subject: [PATCH 10/10] feat: shares for UniversalDelegator --- script/test/UniversalDelegator.s.sol | 16 +- spec/delegator/UniversalDelegator.md | 19 +- src/contracts/delegator/BaseDelegator.sol | 2 - .../delegator/UniversalDelegator.sol | 540 ++++++++++++---- src/contracts/slasher/BaseSlasher.sol | 1 + src/contracts/slasher/UniversalSlasher.sol | 354 ++++++++++ .../delegator/IUniversalDelegator.sol | 185 +++++- src/interfaces/slasher/IUniversalSlasher.sol | 280 ++++++++ test/delegator/UniversalDelegator.t.sol | 602 ++++++++++++++---- .../pages/UniversalDelegatorConfigurator.tsx | 38 +- 10 files changed, 1733 insertions(+), 304 deletions(-) create mode 100644 src/contracts/slasher/UniversalSlasher.sol create mode 100644 src/interfaces/slasher/IUniversalSlasher.sol diff --git a/script/test/UniversalDelegator.s.sol b/script/test/UniversalDelegator.s.sol index e92e3f88..908a04ce 100644 --- a/script/test/UniversalDelegator.s.sol +++ b/script/test/UniversalDelegator.s.sol @@ -78,8 +78,18 @@ contract UniversalDelegatorUiSetup is Script { IBaseDelegator.BaseParams memory baseParams = IBaseDelegator.BaseParams({ defaultAdminRoleHolder: broadcaster, hook: address(0), hookSetRoleHolder: broadcaster }); - IUniversalDelegator.InitParams memory initParams = - IUniversalDelegator.InitParams({baseParams: baseParams, curatorRoleHolder: broadcaster}); + IUniversalDelegator.InitParams memory initParams = IUniversalDelegator.InitParams({ + baseParams: baseParams, + createSlotRoleHolder: broadcaster, + setIsSharedRoleHolder: broadcaster, + setSizeRoleHolder: broadcaster, + setShareRoleHolder: broadcaster, + swapSlotsRoleHolder: broadcaster, + assignNetworkRoleHolder: broadcaster, + unassignNetworkRoleHolder: broadcaster, + assignOperatorRoleHolder: broadcaster, + unassignOperatorRoleHolder: broadcaster + }); bytes memory initCalldata = abi.encodeCall(IEntity.initialize, (abi.encode(address(vault), abi.encode(initParams)))); @@ -88,7 +98,7 @@ contract UniversalDelegatorUiSetup is Script { vm.stopBroadcast(); - console2.log("Curator/admin:", broadcaster); + console2.log("Role holder/admin:", broadcaster); console2.log("Vault (mock):", address(vault)); console2.log("Vault activeStake:", vault.activeStake()); console2.log("Vault epochDuration:", uint256(vault.epochDuration())); diff --git a/spec/delegator/UniversalDelegator.md b/spec/delegator/UniversalDelegator.md index fce1143b..16bb6ed4 100644 --- a/spec/delegator/UniversalDelegator.md +++ b/spec/delegator/UniversalDelegator.md @@ -171,7 +171,7 @@ Operator assignment is tracked historically via `operatorToSlot[parentIndex][ope ## Restaking detection -`isRestaked(subnetwork, operator)` and `isRestakedAt(subnetwork, operator, t, ...)` return `true` when the operator’s slot has any **shared ancestor**: +`isShared(subnetwork, operator)` and `isSharedAt(subnetwork, operator, t, ...)` return `true` when the operator’s slot has any **shared ancestor**: - Walks up from the operator slot’s parent to the root. - Returns `true` if any `slots[ancestor].isShared` is `1`. @@ -199,11 +199,24 @@ Some `*At(...)` view functions accept `bytes hints` to speed up checkpoint looku ```solidity IUniversalDelegator.StakeHints({ baseHints: /* hints forwarded to BaseDelegator opt-in checks */, - allocatedHints: /* hints forwarded into allocation lookups */ + allocatedHints: /* ABI-encoded AllocatedByOperatorAtHints */ }); ``` -`UniversalDelegator` uses `allocatedHints` across multiple checkpoint traces. If you are not certain hints match the queried trace, pass empty bytes (`""`) to avoid reverts. +Other `*At(...)` methods accept ABI-encoded hint structs defined in `IUniversalDelegator`, for example: + +- `BalanceAtHints` (`activeStakeHint`, `allocatedHints`) +- `AvailableAtHints` (`balanceHints`, `pendingFreeHint`, `pendingFreeEpochHint`) +- `AllocatedAtHints` (`sizeHint`, `availableHints`, `prevSumHint`) +- `AllocatedByOperatorAtHints` (`slotOfHints`, `allocatedHints`) +- `SlotOfNetworkAtHints` (`networkSlotHint`) +- `SlotOfOperatorAtHints` (`operatorSlotHint`) +- `SlotOfAtHints` (`slotOfNetworkHints`, `slotOfOperatorHints`) +- `IsSharedAtHints` (`slotOfHints`, `networkIsSharedHint`, `groupIsSharedHint`) + +Nested `*Hints` fields are ABI-encoded hints for the referenced `*At(...)` function. + +If you are not certain hints match the queried trace, pass empty bytes (`""`) to avoid reverts. ## Caveats diff --git a/src/contracts/delegator/BaseDelegator.sol b/src/contracts/delegator/BaseDelegator.sol index 03c821f0..72efce88 100644 --- a/src/contracts/delegator/BaseDelegator.sol +++ b/src/contracts/delegator/BaseDelegator.sol @@ -181,8 +181,6 @@ abstract contract BaseDelegator is revert NotSlasher(); } - _onSlash(subnetwork, operator, amount, captureTimestamp, data); - address hook_ = hook; if (hook_ != address(0)) { bytes memory calldata_ = diff --git a/src/contracts/delegator/UniversalDelegator.sol b/src/contracts/delegator/UniversalDelegator.sol index 6f2613ef..759e5c57 100644 --- a/src/contracts/delegator/UniversalDelegator.sol +++ b/src/contracts/delegator/UniversalDelegator.sol @@ -9,6 +9,7 @@ import {UniversalDelegatorIndex} from "../libraries/UniversalDelegatorIndex.sol" import {IBaseDelegator} from "../../interfaces/delegator/IBaseDelegator.sol"; import {IUniversalDelegator} from "../../interfaces/delegator/IUniversalDelegator.sol"; import {IVault} from "../../interfaces/vault/IVault.sol"; +import {IMigratableEntity} from "../../interfaces/common/IMigratableEntity.sol"; import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; import {MulticallUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/MulticallUpgradeable.sol"; @@ -19,24 +20,32 @@ contract UniversalDelegator is BaseDelegator, MulticallUpgradeable, IUniversalDe using Checkpoints for Checkpoints.Trace208; using Math for uint256; - struct Slot { - uint32[] children; - mapping(uint96 => uint32) childToLocalIndex; - Checkpoints.Trace256 size; - Checkpoints.Trace256 prevSum; - Checkpoints.Trace208 isShared; - Checkpoints.Trace256 pendingFreeCumulative; - } - - bytes32 public constant CURATOR_ROLE = keccak256("CURATOR_ROLE"); + uint256 public constant MAX_SHARES = 1e27; + bytes32 public constant CREATE_SLOT_ROLE = keccak256("CREATE_SLOT_ROLE"); + bytes32 public constant SET_IS_SHARED_ROLE = keccak256("SET_IS_SHARED_ROLE"); + bytes32 public constant SET_SIZE_ROLE = keccak256("SET_SIZE_ROLE"); + bytes32 public constant SET_SHARE_ROLE = keccak256("SET_SHARE_ROLE"); + bytes32 public constant SWAP_SLOTS_ROLE = keccak256("SWAP_SLOTS_ROLE"); + bytes32 public constant ASSIGN_NETWORK_ROLE = keccak256("ASSIGN_NETWORK_ROLE"); + bytes32 public constant UNASSIGN_NETWORK_ROLE = keccak256("UNASSIGN_NETWORK_ROLE"); + bytes32 public constant ASSIGN_OPERATOR_ROLE = keccak256("ASSIGN_OPERATOR_ROLE"); + bytes32 public constant UNASSIGN_OPERATOR_ROLE = keccak256("UNASSIGN_OPERATOR_ROLE"); // @dev index is {32 bytes of child index at depth 1}{32 bytes - depth 2}{32 bytes - depth 3} - mapping(uint96 index => Slot slot) public slots; + mapping(uint96 index => SlotStorage slot) internal slots; mapping(bytes32 subnetwork => Checkpoints.Trace208) internal _networkToSlot; + mapping(uint96 index => bytes32 subnetwork) internal _slotToNetwork; mapping(uint96 parentIndex => mapping(address operator => Checkpoints.Trace208)) internal _operatorToSlot; - mapping(uint96 index => address operator) public operatorBySlot; + mapping(uint96 index => address operator) internal _slotToOperator; mapping(uint96 index => Checkpoints.Trace256 amount) internal _cumulativeSlash; + modifier slotCreated(uint96 index) { + if (index > 0 && index.getChildIndex() > slots[index.getParentIndex()].children.length) { + revert SlotNotCreated(); + } + _; + } + constructor( address networkRegistry, address vaultFactory, @@ -55,7 +64,26 @@ contract UniversalDelegator is BaseDelegator, MulticallUpgradeable, IUniversalDe ) {} - // @dev Returns the collateral balance of a given slot. + /** + * @inheritdoc IUniversalDelegator + */ + function getSlot(uint96 index) public view returns (Slot memory) { + return Slot({ + children: slots[index].children, + size: slots[index].size.latest(), + share: slots[index].share.latest(), + totalChildrenShares: slots[index].totalChildrenShares, + prevSum: slots[index].prevSum.latest(), + isShared: slots[index].isShared.latest(), + totalChildrenSize: slots[index].totalChildrenSize.latest(), + pendingFreeCumulative: slots[index].pendingFreeCumulative.latest() + }); + } + + /** + * @inheritdoc IUniversalDelegator + * @dev Returns the collateral balance of a given slot. + */ function getBalanceAt(uint96 index, uint48 timestamp, bytes memory hints) public view returns (uint256) { if (index == 0) { return IVault(vault).activeStakeAt(timestamp, hints); @@ -63,6 +91,9 @@ contract UniversalDelegator is BaseDelegator, MulticallUpgradeable, IUniversalDe return getAllocatedAt(index, timestamp, hints); } + /** + * @inheritdoc IUniversalDelegator + */ function getBalance(uint96 index) public view returns (uint256) { if (index == 0) { return IVault(vault).activeStake(); @@ -70,18 +101,29 @@ contract UniversalDelegator is BaseDelegator, MulticallUpgradeable, IUniversalDe return getAllocated(index); } - // @dev Returns the available to allocate balance in the given slot. + /** + * @inheritdoc IUniversalDelegator + * @dev Returns the available to allocate balance in the given slot. + */ function getAvailableAt(uint96 index, uint48 timestamp, bytes memory hints) public view returns (uint256) { - return getBalanceAt(index, timestamp, hints) + AvailableHints memory availableHints; + if (hints.length > 0) { + availableHints = abi.decode(hints, (AvailableHints)); + } + return getBalanceAt(index, timestamp, availableHints.balanceHints) .saturatingSub( - slots[index].pendingFreeCumulative.upperLookupRecent(timestamp, hints) + slots[index].pendingFreeCumulative.upperLookupRecent(timestamp, availableHints.pendingFreeHint) - slots[index].pendingFreeCumulative .upperLookupRecent( - uint48(uint256(timestamp).saturatingSub(IVault(vault).epochDuration())), hints + uint48(uint256(timestamp).saturatingSub(IVault(vault).epochDuration())), + availableHints.pendingFreeEpochHint ) ); } + /** + * @inheritdoc IUniversalDelegator + */ function getAvailable(uint96 index) public view returns (uint256) { return getBalance(index) .saturatingSub( @@ -91,55 +133,94 @@ contract UniversalDelegator is BaseDelegator, MulticallUpgradeable, IUniversalDe ); } - // @dev Returns the allocation of the given slot. + /** + * @inheritdoc IUniversalDelegator + * @dev Returns the allocation of the given slot. + */ function getAllocatedAt(uint96 index, uint48 timestamp, bytes memory hints) public view returns (uint256) { - uint96 parentIndex = index.getParentIndex(); - Slot storage parent = slots[parentIndex]; - uint256 available = getAvailableAt(parentIndex, timestamp, hints); - if (parent.isShared.upperLookupRecent(timestamp, hints) == 0) { - available = available.saturatingSub(slots[index].prevSum.upperLookupRecent(timestamp, hints)); + BaseAllocatedHints memory baseAllocatedHints; + if (hints.length > 0) { + baseAllocatedHints = abi.decode(hints, (BaseAllocatedHints)); } - return Math.min(available, slots[index].size.upperLookupRecent(timestamp, hints)); - } - + uint256 size = slots[index].size.upperLookupRecent(timestamp, baseAllocatedHints.sizeHint); + uint256 unallocatedBySizes = + _getParentUnallocatedBySizesAt(index, timestamp, baseAllocatedHints.unallocatedHints); + if (unallocatedBySizes > 0) { + return size + + uint256(slots[index].share.upperLookupRecent(timestamp, baseAllocatedHints.shareOrAvailableHints)) + .mulDiv(unallocatedBySizes, MAX_SHARES); + } + uint256 available = getAvailableAt(index.getParentIndex(), timestamp, baseAllocatedHints.shareOrAvailableHints); + return Math.min( + slots[index.getParentIndex()].isShared.upperLookupRecent(timestamp, baseAllocatedHints.isSharedHint) == 0 + ? available.saturatingSub( + slots[index].prevSum.upperLookupRecent(timestamp, baseAllocatedHints.prevSumHint) + ) + : available, + size + ); + } + + /** + * @inheritdoc IUniversalDelegator + */ function getAllocated(uint96 index) public view returns (uint256) { - uint96 parentIndex = index.getParentIndex(); - Slot storage parent = slots[parentIndex]; - uint256 available = getAvailable(parentIndex); - if (parent.isShared.latest() == 0) { - available = available.saturatingSub(slots[index].prevSum.latest()); + uint256 size = slots[index].size.latest(); + uint256 unallocatedBySizes = _getParentUnallocatedBySizes(index); + if (unallocatedBySizes > 0) { + return size + uint256(slots[index].share.latest()).mulDiv(unallocatedBySizes, MAX_SHARES); } - return Math.min(available, slots[index].size.latest()); - } - + uint256 available = getAvailable(index.getParentIndex()); + return Math.min( + slots[index.getParentIndex()].isShared.latest() == 0 + ? available.saturatingSub(slots[index].prevSum.latest()) + : available, + size + ); + } + + /** + * @inheritdoc IUniversalDelegator + */ function getAllocatedAt(bytes32 subnetwork, address operator, uint48 timestamp, bytes memory hints) public view returns (uint256) { - uint96 index = slotOfAt(subnetwork, operator, timestamp, hints); - return index > 0 ? getAllocatedAt(index, timestamp, hints) : 0; + AllocatedHints memory allocatedHints; + if (hints.length > 0) { + allocatedHints = abi.decode(hints, (AllocatedHints)); + } + uint96 index = getSlotOfAt(subnetwork, operator, timestamp, allocatedHints.slotOfHints); + return index > 0 ? getAllocatedAt(index, timestamp, allocatedHints.allocatedHints) : 0; } + /** + * @inheritdoc IUniversalDelegator + */ function getAllocated(bytes32 subnetwork, address operator) public view returns (uint256) { - uint96 index = slotOf(subnetwork, operator); + uint96 index = getSlotOf(subnetwork, operator); return index > 0 ? getAllocated(index) : 0; } - // @dev Returns the unallocated balance in the given slot (due to pendings or not fully allocated). - function getUnallocated(uint96 index) public view returns (uint256) { - return getAvailable(index).saturatingSub(_getChildrenSize(index)); - } - - function slotOfNetworkAt(bytes32 subnetwork, uint48 timestamp, bytes memory hint) public view returns (uint96) { + /** + * @inheritdoc IUniversalDelegator + */ + function getSlotOfNetworkAt(bytes32 subnetwork, uint48 timestamp, bytes memory hint) public view returns (uint96) { return uint96(_networkToSlot[subnetwork].upperLookupRecent(timestamp, hint)); } - function slotOfNetwork(bytes32 subnetwork) public view returns (uint96) { + /** + * @inheritdoc IUniversalDelegator + */ + function getSlotOfNetwork(bytes32 subnetwork) public view returns (uint96) { return uint96(_networkToSlot[subnetwork].latest()); } - function slotOfOperatorAt(uint96 parentIndex, address operator, uint48 timestamp, bytes memory hint) + /** + * @inheritdoc IUniversalDelegator + */ + function getSlotOfOperatorAt(uint96 parentIndex, address operator, uint48 timestamp, bytes memory hint) public view returns (uint96) @@ -147,121 +228,256 @@ contract UniversalDelegator is BaseDelegator, MulticallUpgradeable, IUniversalDe return uint96(_operatorToSlot[parentIndex][operator].upperLookupRecent(timestamp, hint)); } - function slotOfOperator(uint96 parentIndex, address operator) public view returns (uint96) { + /** + * @inheritdoc IUniversalDelegator + */ + function getSlotOfOperator(uint96 parentIndex, address operator) public view returns (uint96) { return uint96(_operatorToSlot[parentIndex][operator].latest()); } - function slotOfAt(bytes32 subnetwork, address operator, uint48 timestamp, bytes memory hints) + /** + * @inheritdoc IUniversalDelegator + */ + function getSlotOfAt(bytes32 subnetwork, address operator, uint48 timestamp, bytes memory hints) public view returns (uint96) { - return slotOfOperatorAt(slotOfNetworkAt(subnetwork, timestamp, hints), operator, timestamp, hints); + SlotOfHints memory slotOfHints; + if (hints.length > 0) { + slotOfHints = abi.decode(hints, (SlotOfHints)); + } + return getSlotOfOperatorAt( + getSlotOfNetworkAt(subnetwork, timestamp, slotOfHints.slotOfNetworkHints), + operator, + timestamp, + slotOfHints.slotOfOperatorHints + ); } - function slotOf(bytes32 subnetwork, address operator) public view returns (uint96) { - return slotOfOperator(slotOfNetwork(subnetwork), operator); + /** + * @inheritdoc IUniversalDelegator + */ + function getSlotOf(bytes32 subnetwork, address operator) public view returns (uint96) { + return getSlotOfOperator(getSlotOfNetwork(subnetwork), operator); } - function isRestakedAt(bytes32 subnetwork, address operator, uint48 timestamp, bytes memory hints) + /** + * @inheritdoc IUniversalDelegator + */ + function isSharedAt(bytes32 subnetwork, address operator, uint48 timestamp, bytes memory hints) public view returns (bool) { - uint96 index = slotOfAt(subnetwork, operator, timestamp, hints); + IsSharedHints memory isSharedHints; + if (hints.length > 0) { + isSharedHints = abi.decode(hints, (IsSharedHints)); + } + uint96 index = getSlotOfAt(subnetwork, operator, timestamp, isSharedHints.slotOfHints); if (index == 0) { return false; } - for (index = index.getParentIndex(); index > 0; index = index.getParentIndex()) { - if (slots[index].isShared.upperLookupRecent(timestamp, hints) > 0) { - return true; - } - } - return false; + return slots[index.getParentIndex().getParentIndex()].isShared + .upperLookupRecent(timestamp, isSharedHints.isSharedHint) > 0; } - function isRestaked(bytes32 subnetwork, address operator) public view returns (bool) { - uint96 index = slotOf(subnetwork, operator); + /** + * @inheritdoc IUniversalDelegator + */ + function isShared(bytes32 subnetwork, address operator) public view returns (bool) { + uint96 index = getSlotOf(subnetwork, operator); if (index == 0) { return false; } - for (index = index.getParentIndex(); index > 0; index = index.getParentIndex()) { - if (slots[index].isShared.latest() > 0) { - return true; - } - } - return false; + return slots[index.getParentIndex().getParentIndex()].isShared.latest() > 0; } - function createSlot(uint96 parentIndex, bool isShared, uint256 size) public onlyRole(CURATOR_ROLE) { + /** + * @inheritdoc IUniversalDelegator + */ + function createSlot(uint96 parentIndex, bool isShared, uint256 size, uint208 share) + public + onlyRole(CREATE_SLOT_ROLE) + slotCreated(parentIndex) + { if (isShared && parentIndex.getDepth() > 0) { revert WrongDepth(); } - uint256 numChildren = slots[parentIndex].children.length; + SlotStorage storage parent = slots[parentIndex]; + if (share > MAX_SHARES || (!isShared && parent.totalChildrenShares + share > MAX_SHARES)) { + revert TooManyShares(); + } + uint256 numChildren = parent.children.length; uint32 childIndex = uint32(numChildren) + 1; uint96 index = parentIndex.createIndex(childIndex); - Slot storage slot = slots[index]; - slot.prevSum.push(uint48(block.timestamp), _getChildrenSize(parentIndex)); + SlotStorage storage slot = slots[index]; + uint256 totalChildrenSize = parent.totalChildrenSize.latest(); + slot.prevSum.push(uint48(block.timestamp), totalChildrenSize); slot.isShared.push(uint48(block.timestamp), isShared ? 1 : 0); slot.size.push(uint48(block.timestamp), size); - Slot storage parent = slots[parentIndex]; + parent.totalChildrenSize.push(uint48(block.timestamp), totalChildrenSize + size); + slot.share.push(uint48(block.timestamp), share); + parent.totalChildrenShares += share; parent.children.push(childIndex); parent.childToLocalIndex[index] = uint32(numChildren); emit CreateSlot(index, size); } - function setIsShared(uint96 index, bool isShared) public onlyRole(CURATOR_ROLE) { + /** + * @inheritdoc IUniversalDelegator + */ + function setIsShared(uint96 index, bool isShared) public onlyRole(SET_IS_SHARED_ROLE) slotCreated(index) { if (index.getDepth() != 1) { revert WrongDepth(); } - Slot storage slot = slots[index]; + SlotStorage storage slot = slots[index]; if (slot.isShared.latest() == (isShared ? 1 : 0)) { revert IsSharedNotChanged(); } if (getAllocated(index) > 0) { revert SlotAllocated(); } + if (!isShared && slot.totalChildrenShares > MAX_SHARES) { + revert TooManyShares(); + } slot.isShared.push(uint48(block.timestamp), isShared ? 1 : 0); emit SetIsShared(index, isShared); } - // @dev if size increase: just change the size if slot not fully allocated or last child, otherwise use unallocated funds - // @dev if size decrease: just change the size if slot not allocated, otherwise increase pending free - function setSize(uint96 index, uint256 size) public onlyRole(CURATOR_ROLE) { - Slot storage slot = slots[index]; + /** + * @inheritdoc IUniversalDelegator + * @dev if size increase: just change the size if slot is shared or out of available liquidity, otherwise use unallocated funds with dependency of shares + * if size decrease: just change the size if slot is isolated and out of available liquidity, otherwise increase pending + */ + function setSize(uint96 index, uint256 size) + public + onlyRole(SET_SIZE_ROLE) + slotCreated(index) + returns (uint256 pending) + { + SlotStorage storage slot = slots[index]; + uint256 currentSize = slot.size.latest(); + if (currentSize == size) { + revert AlreadySet(); + } uint96 parentIndex = index.getParentIndex(); - Slot storage parent = slots[parentIndex]; - if (size > slot.size.latest()) { - if ( - parent.isShared.latest() == 0 && slot.prevSum.latest() + slot.size.latest() < getAvailable(parentIndex) - && parent.childToLocalIndex[index] < parent.children.length - 1 - && size - slot.size.latest() > getUnallocated(parentIndex) - ) { - revert NotEnoughAvailable(); + SlotStorage storage parent = slots[parentIndex]; + uint256 prevSum = slot.prevSum.latest(); + uint256 available = getAvailable(parentIndex); + uint256 unallocatedBySizes = _getParentUnallocatedBySizes(index); + if (size > currentSize) { + if (parent.isShared.latest() == 0) { + if (unallocatedBySizes == 0) { + if ( + prevSum + currentSize < available + && parent.childToLocalIndex[index] < parent.children.length - 1 + ) { + revert NotEnoughAvailable(); + } + } else { + // derive by knowing that "pending" must be accounted on size increase for neighbor slots with shares + // and "available" decrease by "pending" affects all slots + uint256 neighborShares = parent.totalChildrenShares - slot.share.latest(); + if (neighborShares == MAX_SHARES) { + revert NotEnoughAvailable(); + } + uint256 delta = size - currentSize; + pending = neighborShares.mulDiv(delta, MAX_SHARES - neighborShares, Math.Rounding.Ceil); + // TODO: also allow not just last child, but last child with size? + if ( + parent.childToLocalIndex[index] < parent.children.length - 1 + && delta > unallocatedBySizes.saturatingSub(pending) + ) { + revert NotEnoughAvailable(); + } + } } } else { - if (getAllocated(index) > size) { - parent.pendingFreeCumulative - .push(uint48(block.timestamp), getAllocated(index) - size + parent.pendingFreeCumulative.latest()); + // derive by knowing that "pending" must be accounted on size decrease for original slot + // and, potentially, for neighbor slots with shares + // and "available" decrease by "pending" affects all slots + if (parent.isShared.latest() > 0) { + pending = currentSize < available ? currentSize - size : available.saturatingSub(size); + } else if (unallocatedBySizes > 0 || prevSum < available) { + pending = + prevSum + currentSize < available ? currentSize - size : available.saturatingSub(prevSum + size); } } - slot.size.push(uint48(block.timestamp), size); + if (pending > 0) { + parent.pendingFreeCumulative.push(uint48(block.timestamp), parent.pendingFreeCumulative.latest() + pending); + } + slot.size.push(uint48(block.timestamp), size); + parent.totalChildrenSize.push(uint48(block.timestamp), parent.totalChildrenSize.latest() - currentSize + size); _syncPrevSums(index); emit SetSize(index, size); } - function swapSlots(uint96 index1, uint96 index2) public onlyRole(CURATOR_ROLE) { - Slot storage slot1 = slots[index1]; - Slot storage slot2 = slots[index2]; + /** + * @inheritdoc IUniversalDelegator + * @dev if share increase: just change the share if enough shares available for isolated slots, otherwise revert + * if share decrease: just change the share if no unallocated funds for sizes, otherwise increase pending + */ + function setShare(uint96 index, uint208 share) + public + onlyRole(SET_SHARE_ROLE) + slotCreated(index) + returns (uint256 pending) + { + SlotStorage storage slot = slots[index]; + uint256 currentShare = slot.share.latest(); + if (currentShare == share) { + revert AlreadySet(); + } + uint96 parentIndex = index.getParentIndex(); + SlotStorage storage parent = slots[parentIndex]; + if (share > currentShare) { + if ( + share > MAX_SHARES + || (parent.isShared.latest() == 0 && parent.totalChildrenShares - currentShare + share > MAX_SHARES) + ) { + revert TooManyShares(); + } + } else { + uint256 unallocatedBySizes = _getParentUnallocatedBySizes(index); + if (unallocatedBySizes > 0) { + // derive by knowing that "pending" must be accounted on share decrease for original slot + // and "available" decrease by "pending" affects all slots + pending = unallocatedBySizes.mulDiv(currentShare - share, MAX_SHARES - share, Math.Rounding.Ceil); + } + } + if (pending > 0) { + parent.pendingFreeCumulative.push(uint48(block.timestamp), parent.pendingFreeCumulative.latest() + pending); + } + slot.share.push(uint48(block.timestamp), share); + parent.totalChildrenShares = parent.totalChildrenShares - currentShare + share; + + emit SetShare(index, share); + } + + /** + * @inheritdoc IUniversalDelegator + */ + function swapSlots(uint96 index1, uint96 index2) + public + onlyRole(SWAP_SLOTS_ROLE) + slotCreated(index1) + slotCreated(index2) + { + SlotStorage storage slot1 = slots[index1]; + SlotStorage storage slot2 = slots[index2]; uint96 parentIndex = index1.getParentIndex(); if (parentIndex != index2.getParentIndex()) { revert NotSameParent(); } - Slot storage parent = slots[parentIndex]; + SlotStorage storage parent = slots[parentIndex]; + if (parent.isShared.latest() > 0) { + revert IsShared(); + } (uint32 localIndex1, uint32 localIndex2) = (parent.childToLocalIndex[index1], parent.childToLocalIndex[index2]); if (localIndex1 >= localIndex2) { revert WrongOrder(); @@ -284,20 +500,27 @@ contract UniversalDelegator is BaseDelegator, MulticallUpgradeable, IUniversalDe emit SwapSlots(index1, index2); } - function assignNetwork(uint96 index, bytes32 subnetwork) public onlyRole(CURATOR_ROLE) { + /** + * @inheritdoc IUniversalDelegator + */ + function assignNetwork(uint96 index, bytes32 subnetwork) public onlyRole(ASSIGN_NETWORK_ROLE) slotCreated(index) { if (index.getDepth() != 2) { revert WrongDepth(); } - if (slotOfNetwork(subnetwork) > 0) { + if (_slotToNetwork[index] != bytes32(0) || getSlotOfNetwork(subnetwork) > 0) { revert NetworkAlreadyAssigned(); } _networkToSlot[subnetwork].push(uint48(block.timestamp), index); + _slotToNetwork[index] = subnetwork; emit AssignNetwork(index, subnetwork); } - function unassignNetwork(bytes32 subnetwork) public onlyRole(CURATOR_ROLE) { - uint96 index = slotOfNetwork(subnetwork); + /** + * @inheritdoc IUniversalDelegator + */ + function unassignNetwork(bytes32 subnetwork) public onlyRole(UNASSIGN_NETWORK_ROLE) { + uint96 index = getSlotOfNetwork(subnetwork); if (index == 0) { revert NetworkNotAssigned(); } @@ -305,26 +528,33 @@ contract UniversalDelegator is BaseDelegator, MulticallUpgradeable, IUniversalDe revert SlotAllocated(); } _networkToSlot[subnetwork].push(uint48(block.timestamp), 0); + _slotToNetwork[index] = bytes32(0); emit UnassignNetwork(subnetwork); } - function assignOperator(uint96 index, address operator) public onlyRole(CURATOR_ROLE) { + /** + * @inheritdoc IUniversalDelegator + */ + function assignOperator(uint96 index, address operator) public onlyRole(ASSIGN_OPERATOR_ROLE) slotCreated(index) { if (index.getDepth() != 3) { revert WrongDepth(); } uint96 parentIndex = index.getParentIndex(); - if (slotOfOperator(parentIndex, operator) != 0) { + if (_slotToOperator[index] != address(0) || getSlotOfOperator(parentIndex, operator) != 0) { revert OperatorAlreadyAssigned(); } _operatorToSlot[parentIndex][operator].push(uint48(block.timestamp), index); - operatorBySlot[index] = operator; + _slotToOperator[index] = operator; emit AssignOperator(index, operator); } - function unassignOperator(uint96 parentIndex, address operator) public onlyRole(CURATOR_ROLE) { - uint96 index = slotOfOperator(parentIndex, operator); + /** + * @inheritdoc IUniversalDelegator + */ + function unassignOperator(uint96 parentIndex, address operator) public onlyRole(UNASSIGN_OPERATOR_ROLE) { + uint96 index = getSlotOfOperator(parentIndex, operator); if (index == 0) { revert OperatorNotAssigned(); } @@ -332,28 +562,49 @@ contract UniversalDelegator is BaseDelegator, MulticallUpgradeable, IUniversalDe revert SlotAllocated(); } _operatorToSlot[parentIndex][operator].push(uint48(block.timestamp), 0); - delete operatorBySlot[index]; + _slotToOperator[index] = address(0); emit UnassignOperator(index, operator); } - function _getChildrenSize(uint96 index) internal view returns (uint256) { - uint256 numChildren = slots[index].children.length; - if (numChildren == 0) { - return 0; + function _getParentUnallocatedBySizesAt(uint96 index, uint48 timestamp, bytes memory hints) + internal + view + returns (uint256) + { + UnallocatedBySizesHints memory unallocatedBySizesHints; + if (hints.length > 0) { + unallocatedBySizesHints = abi.decode(hints, (UnallocatedBySizesHints)); } - Slot storage child = slots[index.createIndex(slots[index].children[numChildren - 1])]; - return child.prevSum.latest() + child.size.latest(); + uint96 parentIndex = index.getParentIndex(); + SlotStorage storage parent = slots[parentIndex]; + return getAvailableAt(parentIndex, timestamp, unallocatedBySizesHints.availableHints) + .saturatingSub( + parent.isShared.upperLookupRecent(timestamp, unallocatedBySizesHints.isSharedHint) == 0 + ? parent.totalChildrenSize + .upperLookupRecent(timestamp, unallocatedBySizesHints.totalChildrenSizeOrSizeHint) + : slots[index].size + .upperLookupRecent(timestamp, unallocatedBySizesHints.totalChildrenSizeOrSizeHint) + ); + } + + function _getParentUnallocatedBySizes(uint96 index) internal view returns (uint256) { + uint96 parentIndex = index.getParentIndex(); + SlotStorage storage parent = slots[parentIndex]; + return getAvailable(parentIndex) + .saturatingSub( + parent.isShared.latest() == 0 ? parent.totalChildrenSize.latest() : slots[index].size.latest() + ); } function _syncPrevSums(uint96 startIndex) internal { - Slot storage slot = slots[startIndex]; + SlotStorage storage slot = slots[startIndex]; uint96 parentIndex = startIndex.getParentIndex(); - Slot storage parent = slots[parentIndex]; + SlotStorage storage parent = slots[parentIndex]; uint256 prevSum = slot.prevSum.latest() + slot.size.latest(); uint256 numChildren = parent.children.length; for (uint32 i = parent.childToLocalIndex[startIndex] + 1; i < numChildren; ++i) { - Slot storage child = slots[parentIndex.createIndex(parent.children[i])]; + SlotStorage storage child = slots[parentIndex.createIndex(parent.children[i])]; child.prevSum.push(uint48(block.timestamp), prevSum); prevSum += child.size.latest(); } @@ -365,54 +616,61 @@ contract UniversalDelegator is BaseDelegator, MulticallUpgradeable, IUniversalDe override returns (uint256, bytes memory) { - StakeHints memory stakesHints; + StakeHints memory stakeHints; if (hints.length > 0) { - stakesHints = abi.decode(hints, (StakeHints)); + stakeHints = abi.decode(hints, (StakeHints)); } - return (getAllocatedAt(subnetwork, operator, timestamp, stakesHints.allocatedHints), stakesHints.baseHints); + return (getAllocatedAt(subnetwork, operator, timestamp, stakeHints.allocatedHints), stakeHints.baseHints); } function _stake(bytes32 subnetwork, address operator) internal view override returns (uint256) { return getAllocated(subnetwork, operator); } - function _setMaxNetworkLimit(bytes32 subnetwork, uint256 amount) internal override {} + function _setMaxNetworkLimit(bytes32, uint256) internal override {} - function _onSlash( - bytes32 subnetwork, - address operator, - uint256 amount, - uint48 captureTimestamp, - bytes memory /*data*/ - ) + function __initialize(address vault_, bytes memory data) internal override + returns (IBaseDelegator.BaseParams memory) { - uint96 groupIndex = - slotOfAt(subnetwork, operator, captureTimestamp, new bytes(0)).getParentIndex().getParentIndex(); - - uint256 latestCumulativeSlash = _cumulativeSlash[groupIndex].latest(); - if ( - amount - > getAllocatedAt(groupIndex, captureTimestamp, new bytes(0)) - .saturatingSub( - latestCumulativeSlash - _cumulativeSlash[groupIndex].upperLookupRecent(captureTimestamp) - ) - ) { - revert(); + if (IMigratableEntity(vault_).version() == 1) { + revert OldVault(); } - _cumulativeSlash[groupIndex].push(uint48(block.timestamp), latestCumulativeSlash + amount); - } - - function __initialize(address, bytes memory data) internal override returns (IBaseDelegator.BaseParams memory) { InitParams memory params = abi.decode(data, (InitParams)); - if (params.baseParams.defaultAdminRoleHolder == address(0) && params.curatorRoleHolder == address(0)) { + if (params.baseParams.defaultAdminRoleHolder == address(0) && params.createSlotRoleHolder == address(0)) { revert MissingRoleHolders(); } - _grantRole(CURATOR_ROLE, params.curatorRoleHolder); + if (params.createSlotRoleHolder != address(0)) { + _grantRole(CREATE_SLOT_ROLE, params.createSlotRoleHolder); + } + if (params.setIsSharedRoleHolder != address(0)) { + _grantRole(SET_IS_SHARED_ROLE, params.setIsSharedRoleHolder); + } + if (params.setSizeRoleHolder != address(0)) { + _grantRole(SET_SIZE_ROLE, params.setSizeRoleHolder); + } + if (params.setShareRoleHolder != address(0)) { + _grantRole(SET_SHARE_ROLE, params.setShareRoleHolder); + } + if (params.swapSlotsRoleHolder != address(0)) { + _grantRole(SWAP_SLOTS_ROLE, params.swapSlotsRoleHolder); + } + if (params.assignNetworkRoleHolder != address(0)) { + _grantRole(ASSIGN_NETWORK_ROLE, params.assignNetworkRoleHolder); + } + if (params.unassignNetworkRoleHolder != address(0)) { + _grantRole(UNASSIGN_NETWORK_ROLE, params.unassignNetworkRoleHolder); + } + if (params.assignOperatorRoleHolder != address(0)) { + _grantRole(ASSIGN_OPERATOR_ROLE, params.assignOperatorRoleHolder); + } + if (params.unassignOperatorRoleHolder != address(0)) { + _grantRole(UNASSIGN_OPERATOR_ROLE, params.unassignOperatorRoleHolder); + } return params.baseParams; } diff --git a/src/contracts/slasher/BaseSlasher.sol b/src/contracts/slasher/BaseSlasher.sol index db86953f..9987af68 100644 --- a/src/contracts/slasher/BaseSlasher.sol +++ b/src/contracts/slasher/BaseSlasher.sol @@ -104,6 +104,7 @@ abstract contract BaseSlasher is Entity, StaticDelegateCallable, ReentrancyGuard function _slashableStake(bytes32 subnetwork, address operator, uint48 captureTimestamp, bytes memory hints) internal view + virtual returns (uint256 slashableStake_, uint256 stakeAmount) { SlashableStakeHints memory slashableStakeHints; diff --git a/src/contracts/slasher/UniversalSlasher.sol b/src/contracts/slasher/UniversalSlasher.sol new file mode 100644 index 00000000..51c02d7c --- /dev/null +++ b/src/contracts/slasher/UniversalSlasher.sol @@ -0,0 +1,354 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.25; + +import {BaseSlasher} from "./BaseSlasher.sol"; + +import {Checkpoints} from "../libraries/Checkpoints.sol"; +import {Subnetwork} from "../libraries/Subnetwork.sol"; +import {UniversalDelegatorIndex} from "../libraries/UniversalDelegatorIndex.sol"; + +import {IRegistry} from "../../interfaces/common/IRegistry.sol"; +import {IVault} from "../../interfaces/vault/IVault.sol"; +import {IUniversalSlasher} from "../../interfaces/slasher/IUniversalSlasher.sol"; +import {IMigratableEntity} from "../../interfaces/common/IMigratableEntity.sol"; +import {IUniversalDelegator} from "../../interfaces/delegator/IUniversalDelegator.sol"; + +import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; +import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol"; +import {Time} from "@openzeppelin/contracts/utils/types/Time.sol"; + +contract VetoSlasher is BaseSlasher, IUniversalSlasher { + using Math for uint256; + using SafeCast for uint256; + using Checkpoints for Checkpoints.Trace208; + using Checkpoints for Checkpoints.Trace256; + using Subnetwork for address; + using UniversalDelegatorIndex for uint96; + + /** + * @inheritdoc IUniversalSlasher + */ + address public immutable NETWORK_REGISTRY; + + /** + * @inheritdoc IUniversalSlasher + */ + SlashRequest[] public slashRequests; + + /** + * @inheritdoc IUniversalSlasher + */ + uint48 public vetoDuration; + + /** + * @inheritdoc IUniversalSlasher + */ + uint256 public resolverSetEpochsDelay; + + mapping(bytes32 subnetwork => Checkpoints.Trace208 value) internal _resolver; + + mapping(uint96 groupIndex => Checkpoints.Trace256 amount) internal _groupCumulativeSlash; + + constructor( + address vaultFactory, + address networkMiddlewareService, + address networkRegistry, + address slasherFactory, + uint64 entityType + ) BaseSlasher(vaultFactory, networkMiddlewareService, slasherFactory, entityType) { + NETWORK_REGISTRY = networkRegistry; + } + + /** + * @inheritdoc IUniversalSlasher + */ + function slashRequestsLength() external view returns (uint256) { + return slashRequests.length; + } + + /** + * @inheritdoc IUniversalSlasher + */ + function resolverAt(bytes32 subnetwork, uint48 timestamp, bytes memory hint) public view returns (address) { + return address(uint160(_resolver[subnetwork].upperLookupRecent(timestamp, hint))); + } + + /** + * @inheritdoc IUniversalSlasher + */ + function resolver(bytes32 subnetwork, bytes memory hint) public view returns (address) { + return resolverAt(subnetwork, Time.timestamp(), hint); + } + + /** + * @inheritdoc IUniversalSlasher + */ + function groupCumulativeSlashAt(uint96 groupIndex, uint48 timestamp, bytes memory hint) + public + view + returns (uint256) + { + return _groupCumulativeSlash[groupIndex].upperLookupRecent(timestamp, hint); + } + + /** + * @inheritdoc IUniversalSlasher + */ + function groupCumulativeSlash(uint96 groupIndex) public view returns (uint256) { + return _groupCumulativeSlash[groupIndex].latest(); + } + + /** + * @inheritdoc IUniversalSlasher + */ + function requestSlash( + bytes32 subnetwork, + address operator, + uint256 amount, + uint48 captureTimestamp, + bytes calldata hints + ) external nonReentrant onlyNetworkMiddleware(subnetwork) returns (uint256 slashIndex) { + RequestSlashHints memory requestSlashHints; + if (hints.length > 0) { + requestSlashHints = abi.decode(hints, (RequestSlashHints)); + } + + if ( + captureTimestamp < Time.timestamp() + vetoDuration - IVault(vault).epochDuration() + || captureTimestamp >= Time.timestamp() + ) { + revert InvalidCaptureTimestamp(); + } + + amount = Math.min( + amount, slashableStake(subnetwork, operator, captureTimestamp, requestSlashHints.slashableStakeHints) + ); + if (amount == 0) { + revert InsufficientSlash(); + } + + uint48 vetoDeadline = Time.timestamp() + vetoDuration; + + slashIndex = slashRequests.length; + slashRequests.push( + SlashRequest({ + subnetwork: subnetwork, + operator: operator, + amount: amount, + captureTimestamp: captureTimestamp, + vetoDeadline: vetoDeadline, + completed: false + }) + ); + + emit RequestSlash(slashIndex, subnetwork, operator, amount, captureTimestamp, vetoDeadline); + } + + /** + * @inheritdoc IUniversalSlasher + */ + function executeSlash(uint256 slashIndex, bytes calldata hints) + external + nonReentrant + returns (uint256 slashedAmount) + { + ExecuteSlashHints memory executeSlashHints; + if (hints.length > 0) { + executeSlashHints = abi.decode(hints, (ExecuteSlashHints)); + } + + if (slashIndex >= slashRequests.length) { + revert SlashRequestNotExist(); + } + + SlashRequest storage request = slashRequests[slashIndex]; + + _checkNetworkMiddleware(request.subnetwork); + + if ( + resolverAt(request.subnetwork, request.captureTimestamp, executeSlashHints.captureResolverHint) + != address(0) + && resolverAt(request.subnetwork, Time.timestamp() - 1, executeSlashHints.currentResolverHint) + != address(0) && request.vetoDeadline > Time.timestamp() + ) { + revert VetoPeriodNotEnded(); + } + + if (Time.timestamp() - request.captureTimestamp > IVault(vault).epochDuration()) { + revert SlashPeriodEnded(); + } + + (uint256 slashableStake_, uint256 stakeAt) = _slashableStake( + request.subnetwork, request.operator, request.captureTimestamp, executeSlashHints.slashableStakeHints + ); + slashedAmount = Math.min(request.amount, slashableStake_); + if (slashedAmount == 0) { + revert InsufficientSlash(); + } + + if (request.completed) { + revert SlashRequestCompleted(); + } + + request.completed = true; + + _updateLatestSlashedCaptureTimestamp(request.subnetwork, request.operator, request.captureTimestamp); + + _updateCumulativeSlash(request.subnetwork, request.operator, slashedAmount); + + _delegatorOnSlash( + request.subnetwork, + request.operator, + slashedAmount, + request.captureTimestamp, + abi.encode( + IUniversalSlasher.DelegatorData({ + slashableStake: slashableStake_, stakeAt: stakeAt, slashIndex: slashIndex + }) + ) + ); + + _vaultOnSlash(slashedAmount, request.captureTimestamp); + + _burnerOnSlash(request.subnetwork, request.operator, slashedAmount, request.captureTimestamp); + + emit ExecuteSlash(slashIndex, slashedAmount); + } + + /** + * @inheritdoc IUniversalSlasher + */ + function vetoSlash(uint256 slashIndex, bytes calldata hints) external nonReentrant { + VetoSlashHints memory vetoSlashHints; + if (hints.length > 0) { + vetoSlashHints = abi.decode(hints, (VetoSlashHints)); + } + + if (slashIndex >= slashRequests.length) { + revert SlashRequestNotExist(); + } + + SlashRequest storage request = slashRequests[slashIndex]; + + address captureResolver = + resolverAt(request.subnetwork, request.captureTimestamp, vetoSlashHints.captureResolverHint); + if ( + captureResolver == address(0) + || resolverAt(request.subnetwork, Time.timestamp() - 1, vetoSlashHints.currentResolverHint) + == address(0) + ) { + revert NoResolver(); + } + + if (msg.sender != captureResolver) { + revert NotResolver(); + } + + if (request.vetoDeadline <= Time.timestamp()) { + revert VetoPeriodEnded(); + } + + if (request.completed) { + revert SlashRequestCompleted(); + } + + request.completed = true; + + emit VetoSlash(slashIndex, msg.sender); + } + + function setResolver(uint96 identifier, address resolver_, bytes calldata hints) external nonReentrant { + SetResolverHints memory setResolverHints; + if (hints.length > 0) { + setResolverHints = abi.decode(hints, (SetResolverHints)); + } + + if (!IRegistry(NETWORK_REGISTRY).isEntity(msg.sender)) { + revert NotNetwork(); + } + + address vault_ = vault; + bytes32 subnetwork = (msg.sender).subnetwork(identifier); + (bool exists, uint48 latestTimestamp,) = _resolver[subnetwork].latestCheckpoint(); + if (exists) { + if (latestTimestamp > Time.timestamp()) { + _resolver[subnetwork].pop(); + } else if (resolver_ == address(uint160(_resolver[subnetwork].latest()))) { + revert AlreadySet(); + } + + if (resolver_ != address(uint160(_resolver[subnetwork].latest()))) { + _resolver[subnetwork].push( + (IVault(vault_).currentEpochStart() + resolverSetEpochsDelay * IVault(vault_).epochDuration()) + .toUint48(), + uint160(resolver_) + ); + } + } else { + if (resolver_ == address(0)) { + revert AlreadySet(); + } + + _resolver[subnetwork].push(Time.timestamp(), uint160(resolver_)); + } + + emit SetResolver(subnetwork, resolver_); + } + + function _slashableStake(bytes32 subnetwork, address operator, uint48 captureTimestamp, bytes memory hints) + internal + view + override + returns (uint256 slashableStake_, uint256 stakeAmount) + { + OuterSlashableStakeHints memory outerSlashableStakeHints; + if (hints.length > 0) { + outerSlashableStakeHints = abi.decode(hints, (OuterSlashableStakeHints)); + } + address delegator = IVault(vault).delegator(); + uint96 groupIndex = IUniversalDelegator(delegator) + .getSlotOfAt(subnetwork, operator, captureTimestamp, outerSlashableStakeHints.slotOfHints).getParentIndex() + .getParentIndex(); + uint256 groupAllocatedAmount = IUniversalDelegator(delegator) + .getAllocatedAt(groupIndex, captureTimestamp, outerSlashableStakeHints.groupAllocatedHints); + (slashableStake_, stakeAmount) = + super._slashableStake(subnetwork, operator, captureTimestamp, outerSlashableStakeHints.slashableStakeHints); + return ( + Math.min( + slashableStake_, + groupAllocatedAmount + - Math.min( + groupCumulativeSlash(groupIndex) + - groupCumulativeSlashAt( + groupIndex, captureTimestamp, outerSlashableStakeHints.groupCumulativeSlashFromHint + ), + groupAllocatedAmount + ) + ), + stakeAmount + ); + } + + function __initialize(address vault_, bytes memory data) internal override returns (BaseParams memory) { + if (IMigratableEntity(vault_).version() == 1) { + revert OldVault(); + } + + (InitParams memory params) = abi.decode(data, (InitParams)); + + uint48 epochDuration = IVault(vault_).epochDuration(); + if (params.vetoDuration >= epochDuration) { + revert InvalidVetoDuration(); + } + + if (params.resolverSetEpochsDelay < 3) { + revert InvalidResolverSetEpochsDelay(); + } + + vetoDuration = params.vetoDuration; + + resolverSetEpochsDelay = params.resolverSetEpochsDelay; + + return params.baseParams; + } +} diff --git a/src/interfaces/delegator/IUniversalDelegator.sol b/src/interfaces/delegator/IUniversalDelegator.sol index aa54805a..fc8994c7 100644 --- a/src/interfaces/delegator/IUniversalDelegator.sol +++ b/src/interfaces/delegator/IUniversalDelegator.sol @@ -3,6 +3,8 @@ pragma solidity ^0.8.0; import {IBaseDelegator} from "./IBaseDelegator.sol"; +import {Checkpoints} from "../../contracts/libraries/Checkpoints.sol"; + interface IUniversalDelegator is IBaseDelegator { error NotEnoughAvailable(); error NotSameParent(); @@ -17,12 +19,127 @@ interface IUniversalDelegator is IBaseDelegator { error MissingRoleHolders(); error IsSharedNotChanged(); error WrongDepth(); + error TooManyShares(); + error IsShared(); + error SlotNotCreated(); + error OldVault(); struct InitParams { BaseParams baseParams; - address curatorRoleHolder; + address createSlotRoleHolder; + address setIsSharedRoleHolder; + address setSizeRoleHolder; + address setShareRoleHolder; + address swapSlotsRoleHolder; + address assignNetworkRoleHolder; + address unassignNetworkRoleHolder; + address assignOperatorRoleHolder; + address unassignOperatorRoleHolder; + } + + struct SlotStorage { + uint32[] children; + Checkpoints.Trace256 size; + Checkpoints.Trace208 share; + uint256 totalChildrenShares; + Checkpoints.Trace256 prevSum; + Checkpoints.Trace208 isShared; + Checkpoints.Trace256 totalChildrenSize; + Checkpoints.Trace256 pendingFreeCumulative; + mapping(uint96 => uint32) childToLocalIndex; + } + + struct Slot { + uint32[] children; + uint256 size; + uint256 share; + uint256 totalChildrenShares; + uint256 prevSum; + uint256 isShared; + uint256 totalChildrenSize; + uint256 pendingFreeCumulative; + } + + /** + * @notice Hints for a balance lookup. + * @param activeStakeHint hint for the vault active stake checkpoint (used when index == 0) + * @param allocatedHints hints forwarded to getAllocatedAt(uint96,...) + */ + struct BalanceHints { + bytes activeStakeHint; + bytes allocatedHints; + } + + /** + * @notice Hints for an available balance lookup. + * @param balanceHints hints forwarded to getBalanceAt + * @param pendingFreeHint hint for pendingFreeCumulative at the requested timestamp + * @param pendingFreeEpochHint hint for pendingFreeCumulative at (timestamp - epochDuration) + */ + struct AvailableHints { + bytes balanceHints; + bytes pendingFreeHint; + bytes pendingFreeEpochHint; + } + + /** + * @notice Hints for an allocation lookup by slot index. + * @param sizeHint hint for the size checkpoint + * @param unallocatedHints hints forwarded to _getParentUnallocatedBySizesAt(index, timestamp, ...) + * @param shareOrAvailableHints hints forwarded to getAvailableAt(parentIndex,...) + * @param isSharedHint hint for isShared + * @param prevSumHint hint for the prevSum checkpoint + */ + struct BaseAllocatedHints { + bytes sizeHint; + bytes unallocatedHints; + bytes shareOrAvailableHints; + bytes isSharedHint; + bytes prevSumHint; } + /** + * @notice Hints for an allocation lookup by subnetwork/operator. + * @param slotOfHints hints forwarded to getSlotOfAt + * @param allocatedHints hints forwarded to getAllocatedAt(uint96,...) + */ + struct AllocatedHints { + bytes slotOfHints; + bytes allocatedHints; + } + + /** + * @notice Hints for a combined subnetwork/operator slot lookup. + * @param slotOfNetworkHints hints forwarded to getSlotOfNetworkAt + * @param slotOfOperatorHints hints forwarded to getSlotOfOperatorAt + */ + struct SlotOfHints { + bytes slotOfNetworkHints; + bytes slotOfOperatorHints; + } + + /** + * @notice Hints for a restake lookup. + * @param slotOfHints hints forwarded to getSlotOfAt + * @param isSharedHint hint for isShared + */ + struct IsSharedHints { + bytes slotOfHints; + bytes isSharedHint; + } + + struct UnallocatedBySizesHints { + bytes availableHints; + bytes isSharedHint; + bytes totalChildrenSizeOrSizeHint; + } + + /** + * @notice Hints for a stake. + * @param baseHints base hints + * @param allocatedHints hints for getAllocatedAt(subnetwork, operator, timestamp, ...) + * @dev expects ABI-encoded AllocatedByOperatorHints + */ struct StakeHints { bytes baseHints; bytes allocatedHints; @@ -34,6 +151,8 @@ interface IUniversalDelegator is IBaseDelegator { event SetSize(uint96 indexed index, uint256 size); + event SetShare(uint96 indexed index, uint256 share); + event SwapSlots(uint96 indexed index1, uint96 indexed index2); event AssignNetwork(uint96 indexed index, bytes32 indexed subnetwork); @@ -43,4 +162,68 @@ interface IUniversalDelegator is IBaseDelegator { event AssignOperator(uint96 indexed index, address indexed operator); event UnassignOperator(uint96 indexed index, address indexed operator); + + function getSlot(uint96 index) external view returns (Slot memory); + + function getBalanceAt(uint96 index, uint48 timestamp, bytes memory hints) external view returns (uint256); + + function getBalance(uint96 index) external view returns (uint256); + + function getAvailableAt(uint96 index, uint48 timestamp, bytes memory hints) external view returns (uint256); + + function getAvailable(uint96 index) external view returns (uint256); + + function getAllocatedAt(uint96 index, uint48 timestamp, bytes memory hints) external view returns (uint256); + + function getAllocated(uint96 index) external view returns (uint256); + + function getAllocatedAt(bytes32 subnetwork, address operator, uint48 timestamp, bytes memory hints) + external + view + returns (uint256); + + function getAllocated(bytes32 subnetwork, address operator) external view returns (uint256); + + function getSlotOfNetworkAt(bytes32 subnetwork, uint48 timestamp, bytes memory hint) external view returns (uint96); + + function getSlotOfNetwork(bytes32 subnetwork) external view returns (uint96); + + function getSlotOfOperatorAt(uint96 parentIndex, address operator, uint48 timestamp, bytes memory hint) + external + view + returns (uint96); + + function getSlotOfOperator(uint96 parentIndex, address operator) external view returns (uint96); + + function getSlotOfAt(bytes32 subnetwork, address operator, uint48 timestamp, bytes memory hints) + external + view + returns (uint96); + + function getSlotOf(bytes32 subnetwork, address operator) external view returns (uint96); + + function isSharedAt(bytes32 subnetwork, address operator, uint48 timestamp, bytes memory hints) + external + view + returns (bool); + + function isShared(bytes32 subnetwork, address operator) external view returns (bool); + + function createSlot(uint96 parentIndex, bool isShared, uint256 size, uint208 share) external; + + function setIsShared(uint96 index, bool isShared) external; + + function setSize(uint96 index, uint256 size) external returns (uint256 pending); + + function setShare(uint96 index, uint208 share) external returns (uint256 pending); + + function swapSlots(uint96 index1, uint96 index2) external; + + function assignNetwork(uint96 index, bytes32 subnetwork) external; + + function unassignNetwork(bytes32 subnetwork) external; + + function assignOperator(uint96 index, address operator) external; + + function unassignOperator(uint96 index, address operator) external; } diff --git a/src/interfaces/slasher/IUniversalSlasher.sol b/src/interfaces/slasher/IUniversalSlasher.sol new file mode 100644 index 00000000..441e2289 --- /dev/null +++ b/src/interfaces/slasher/IUniversalSlasher.sol @@ -0,0 +1,280 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {IBaseSlasher} from "./IBaseSlasher.sol"; + +interface IUniversalSlasher is IBaseSlasher { + error AlreadySet(); + error InsufficientSlash(); + error InvalidCaptureTimestamp(); + error InvalidResolverSetEpochsDelay(); + error InvalidVetoDuration(); + error NoResolver(); + error NotNetwork(); + error NotResolver(); + error SlashPeriodEnded(); + error SlashRequestCompleted(); + error SlashRequestNotExist(); + error VetoPeriodEnded(); + error VetoPeriodNotEnded(); + error OldVault(); + + /** + * @notice Initial parameters needed for a slasher deployment. + * @param baseParams base parameters for slashers' deployment + * @param vetoDuration duration of the veto period for a slash request + * @param resolverSetEpochsDelay delay in epochs for a network to update a resolver + */ + struct InitParams { + IBaseSlasher.BaseParams baseParams; + uint48 vetoDuration; + uint256 resolverSetEpochsDelay; + } + + /** + * @notice Structure for a slash request. + * @param subnetwork subnetwork that requested the slash + * @param operator operator that could be slashed (if the request is not vetoed) + * @param amount maximum amount of the collateral to be slashed + * @param captureTimestamp time point when the stake was captured + * @param vetoDeadline deadline for the resolver to veto the slash (exclusively) + * @param completed if the slash was vetoed/executed + */ + struct SlashRequest { + bytes32 subnetwork; + address operator; + uint256 amount; + uint48 captureTimestamp; + uint48 vetoDeadline; + bool completed; + } + + /** + * @notice Hints for a slashable stake. + * @param slashableStakeHints hints for the slashable stake checkpoints + * @param slotOfHints hints for the slot lookup + * @param groupAllocatedHints hints for the group allocation lookup + * @param groupCumulativeSlashFromHint hint for the group cumulative slash amount at a capture timestamp + */ + struct OuterSlashableStakeHints { + bytes slashableStakeHints; + bytes slotOfHints; + bytes groupAllocatedHints; + bytes groupCumulativeSlashFromHint; + } + + /** + * @notice Hints for a slash request. + * @param slashableStakeHints hints for the slashable stake checkpoints + */ + struct RequestSlashHints { + bytes slashableStakeHints; + } + + /** + * @notice Hints for a slash execute. + * @param captureResolverHint hint for the resolver checkpoint at the capture time + * @param currentResolverHint hint for the resolver checkpoint at the current time + * @param slashableStakeHints hints for the slashable stake checkpoints + */ + struct ExecuteSlashHints { + bytes captureResolverHint; + bytes currentResolverHint; + bytes slashableStakeHints; + } + + /** + * @notice Hints for a slash veto. + * @param captureResolverHint hint for the resolver checkpoint at the capture time + * @param currentResolverHint hint for the resolver checkpoint at the current time + */ + struct VetoSlashHints { + bytes captureResolverHint; + bytes currentResolverHint; + } + + /** + * @notice Hints for a resolver set. + * @param resolverHint hint for the resolver checkpoint + */ + struct SetResolverHints { + bytes resolverHint; + } + + /** + * @notice Extra data for the delegator. + * @param slashableStake amount of the slashable stake before the slash (cache) + * @param stakeAt amount of the stake at the capture time (cache) + * @param slashIndex index of the slash request + */ + struct DelegatorData { + uint256 slashableStake; + uint256 stakeAt; + uint256 slashIndex; + } + + /** + * @notice Emitted when a slash request is created. + * @param slashIndex index of the slash request + * @param subnetwork subnetwork that requested the slash + * @param operator operator that could be slashed (if the request is not vetoed) + * @param slashAmount maximum amount of the collateral to be slashed + * @param captureTimestamp time point when the stake was captured + * @param vetoDeadline deadline for the resolver to veto the slash (exclusively) + */ + event RequestSlash( + uint256 indexed slashIndex, + bytes32 indexed subnetwork, + address indexed operator, + uint256 slashAmount, + uint48 captureTimestamp, + uint48 vetoDeadline + ); + + /** + * @notice Emitted when a slash request is executed. + * @param slashIndex index of the slash request + * @param slashedAmount virtual amount of the collateral slashed + */ + event ExecuteSlash(uint256 indexed slashIndex, uint256 slashedAmount); + + /** + * @notice Emitted when a slash request is vetoed. + * @param slashIndex index of the slash request + * @param resolver address of the resolver that vetoed the slash + */ + event VetoSlash(uint256 indexed slashIndex, address indexed resolver); + + /** + * @notice Emitted when a resolver is set. + * @param subnetwork full identifier of the subnetwork (address of the network concatenated with the uint96 identifier) + * @param resolver address of the resolver + */ + event SetResolver(bytes32 indexed subnetwork, address resolver); + + /** + * @notice Get the network registry's address. + * @return address of the network registry + */ + function NETWORK_REGISTRY() external view returns (address); + + /** + * @notice Get a duration during which resolvers can veto slash requests. + * @return duration of the veto period + */ + function vetoDuration() external view returns (uint48); + + /** + * @notice Get a total number of slash requests. + * @return total number of slash requests + */ + function slashRequestsLength() external view returns (uint256); + + /** + * @notice Get a particular slash request. + * @param slashIndex index of the slash request + * @return subnetwork subnetwork that requested the slash + * @return operator operator that could be slashed (if the request is not vetoed) + * @return amount maximum amount of the collateral to be slashed + * @return captureTimestamp time point when the stake was captured + * @return vetoDeadline deadline for the resolver to veto the slash (exclusively) + * @return completed if the slash was vetoed/executed + */ + function slashRequests(uint256 slashIndex) + external + view + returns ( + bytes32 subnetwork, + address operator, + uint256 amount, + uint48 captureTimestamp, + uint48 vetoDeadline, + bool completed + ); + + /** + * @notice Get a delay for networks in epochs to update a resolver. + * @return updating resolver delay in epochs + */ + function resolverSetEpochsDelay() external view returns (uint256); + + /** + * @notice Get a resolver for a given subnetwork at a particular timestamp using a hint. + * @param subnetwork full identifier of the subnetwork (address of the network concatenated with the uint96 identifier) + * @param timestamp timestamp to get the resolver at + * @param hint hint for the checkpoint index + * @return address of the resolver + */ + function resolverAt(bytes32 subnetwork, uint48 timestamp, bytes memory hint) external view returns (address); + + /** + * @notice Get a resolver for a given subnetwork using a hint. + * @param subnetwork full identifier of the subnetwork (address of the network concatenated with the uint96 identifier) + * @param hint hint for the checkpoint index + * @return address of the resolver + */ + function resolver(bytes32 subnetwork, bytes memory hint) external view returns (address); + + /** + * @notice Get a group cumulative slash amount for a given group index at a particular timestamp using a hint. + * @param groupIndex index of the group + * @param timestamp timestamp to get the group cumulative slash amount at + * @param hint hint for the checkpoint index + * @return amount of the group cumulative slash + */ + function groupCumulativeSlashAt(uint96 groupIndex, uint48 timestamp, bytes memory hint) + external + view + returns (uint256); + + /** + * @notice Get a group cumulative slash amount for a given group index. + * @param groupIndex index of the group + * @return amount of the group cumulative slash + */ + function groupCumulativeSlash(uint96 groupIndex) external view returns (uint256); + + /** + * @notice Request a slash using a subnetwork for a particular operator by a given amount using hints. + * @param subnetwork full identifier of the subnetwork (address of the network concatenated with the uint96 identifier) + * @param operator address of the operator + * @param amount maximum amount of the collateral to be slashed + * @param captureTimestamp time point when the stake was captured + * @param hints hints for checkpoints' indexes + * @return slashIndex index of the slash request + * @dev Only a network middleware can call this function. + */ + function requestSlash( + bytes32 subnetwork, + address operator, + uint256 amount, + uint48 captureTimestamp, + bytes calldata hints + ) external returns (uint256 slashIndex); + + /** + * @notice Execute a slash with a given slash index using hints. + * @param slashIndex index of the slash request + * @param hints hints for checkpoints' indexes + * @return slashedAmount virtual amount of the collateral slashed + * @dev Only a network middleware can call this function. + */ + function executeSlash(uint256 slashIndex, bytes calldata hints) external returns (uint256 slashedAmount); + + /** + * @notice Veto a slash with a given slash index using hints. + * @param slashIndex index of the slash request + * @param hints hints for checkpoints' indexes + * @dev Only a resolver can call this function. + */ + function vetoSlash(uint256 slashIndex, bytes calldata hints) external; + + /** + * @notice Set a resolver for a subnetwork using hints. + * identifier identifier of the subnetwork + * @param resolver address of the resolver + * @param hints hints for checkpoints' indexes + * @dev Only a network can call this function. + */ + function setResolver(uint96 identifier, address resolver, bytes calldata hints) external; +} diff --git a/test/delegator/UniversalDelegator.t.sol b/test/delegator/UniversalDelegator.t.sol index 4888d32a..0531e4f1 100644 --- a/test/delegator/UniversalDelegator.t.sol +++ b/test/delegator/UniversalDelegator.t.sol @@ -127,9 +127,17 @@ contract UniversalDelegatorTest is Test { delegatorParams: abi.encode( IUniversalDelegator.InitParams({ baseParams: IBaseDelegator.BaseParams({ - defaultAdminRoleHolder: address(0), hook: address(0), hookSetRoleHolder: address(0) + defaultAdminRoleHolder: owner, hook: address(0), hookSetRoleHolder: address(0) }), - curatorRoleHolder: owner + createSlotRoleHolder: owner, + setIsSharedRoleHolder: owner, + setSizeRoleHolder: owner, + setShareRoleHolder: owner, + swapSlotsRoleHolder: owner, + assignNetworkRoleHolder: owner, + unassignNetworkRoleHolder: owner, + assignOperatorRoleHolder: owner, + unassignOperatorRoleHolder: owner }) ), withSlasher: true, @@ -146,7 +154,7 @@ contract UniversalDelegatorTest is Test { } function test_checkpointTracksHistory_andDefaults() public { - delegator.createSlot(0, false, 30); + _createSlot(0, false, 30); uint96 slot1 = uint96(0).createIndex(uint32(1)); assertEq(delegator.getAllocatedAt(slot1, 0, ""), 0); @@ -161,16 +169,45 @@ contract UniversalDelegatorTest is Test { assertEq(delegator.getAllocatedAt(slot1, 9, ""), 20); } + function test_createSlot_root_allowsDepth1() public { + _createSlot(0, false, 10); + uint96 slot1 = uint96(0).createIndex(uint32(1)); + + assertEq(delegator.getAllocated(slot1), 0); + } + + function test_setSize_allowsNonZeroCurrentSize() public { + _createSlot(0, false, 10); + uint96 slot1 = uint96(0).createIndex(uint32(1)); + + delegator.setSize(slot1, 20); + assertEq(delegator.getAllocated(slot1), 0); + } + + function test_setShare_preservesParentTotals() public { + _createSlot(0, false, 1); + _createSlot(0, false, 1); + uint96 slot1 = uint96(0).createIndex(uint32(1)); + uint96 slot2 = uint96(0).createIndex(uint32(2)); + + uint208 halfShares = uint208(delegator.MAX_SHARES() / 2); + delegator.setShare(slot1, halfShares); + delegator.setShare(slot2, halfShares); + + vm.expectRevert(IUniversalDelegator.TooManyShares.selector); + delegator.setShare(slot1, uint208(halfShares + 1)); + } + function test_slotAllocation_partialFill() public { _deposit(alice, 100); - delegator.createSlot(0, false, 30); - delegator.createSlot(0, false, 500); + _createSlot(0, false, 30); + _createSlot(0, false, 500); uint96 slot1 = uint96(0).createIndex(uint32(1)); uint96 slot2 = uint96(0).createIndex(uint32(2)); - assertEq(delegator.getUnallocated(0), 0); + assertEq(_unallocated2(0, slot1, slot2), 0); assertEq(delegator.getAllocated(slot1), 30); assertEq(delegator.getAllocated(slot2), 70); } @@ -178,13 +215,13 @@ contract UniversalDelegatorTest is Test { function test_slotAllocation_partialFill_2() public { _deposit(alice, 100); - delegator.createSlot(0, false, 500); - delegator.createSlot(0, false, 30); + _createSlot(0, false, 500); + _createSlot(0, false, 30); uint96 slot1 = uint96(0).createIndex(uint32(1)); uint96 slot2 = uint96(0).createIndex(uint32(2)); - assertEq(delegator.getUnallocated(0), 0); + assertEq(_unallocated2(0, slot1, slot2), 0); assertEq(delegator.getAllocated(slot1), 100); assertEq(delegator.getAllocated(slot2), 0); } @@ -192,13 +229,13 @@ contract UniversalDelegatorTest is Test { function test_slotAllocation_respectsOrderAndLimits() public { _deposit(alice, 100); - delegator.createSlot(0, false, 30); - delegator.createSlot(0, false, 50); + _createSlot(0, false, 30); + _createSlot(0, false, 50); uint96 slot1 = uint96(0).createIndex(uint32(1)); uint96 slot2 = uint96(0).createIndex(uint32(2)); - assertEq(delegator.getUnallocated(0), 20); + assertEq(_unallocated2(0, slot1, slot2), 20); assertEq(delegator.getAllocated(slot1), 30); assertEq(delegator.getAllocated(slot2), 50); } @@ -206,8 +243,8 @@ contract UniversalDelegatorTest is Test { function test_increaseLimit_consumesUnallocated_andUpdatesPrevSums() public { _deposit(alice, 100); - delegator.createSlot(0, false, 30); - delegator.createSlot(0, false, 50); + _createSlot(0, false, 30); + _createSlot(0, false, 50); uint96 slot1 = uint96(0).createIndex(uint32(1)); uint96 slot2 = uint96(0).createIndex(uint32(2)); @@ -217,14 +254,14 @@ contract UniversalDelegatorTest is Test { assertEq(delegator.getAllocatedAt(slot1, 1, ""), 45); assertEq(delegator.getAllocatedAt(slot2, 1, ""), 50); - assertEq(delegator.getUnallocated(0), 5); + assertEq(_unallocated2(0, slot1, slot2), 5); } function test_increaseLimit_revertsWhenFullyAllocatedNonLast_withoutUnallocated() public { _deposit(alice, 100); - delegator.createSlot(0, false, 60); - delegator.createSlot(0, false, 60); + _createSlot(0, false, 60); + _createSlot(0, false, 60); uint96 slot1 = uint96(0).createIndex(uint32(1)); @@ -235,10 +272,11 @@ contract UniversalDelegatorTest is Test { function test_increaseLimit_allowsWhenNotFullyAllocated_evenIfNotLastChild() public { _deposit(alice, 100); - delegator.createSlot(0, false, 60); - delegator.createSlot(0, false, 60); - delegator.createSlot(0, false, 60); + _createSlot(0, false, 60); + _createSlot(0, false, 60); + _createSlot(0, false, 60); + uint96 slot1 = uint96(0).createIndex(uint32(1)); uint96 slot2 = uint96(0).createIndex(uint32(2)); uint96 slot3 = uint96(0).createIndex(uint32(3)); @@ -246,14 +284,14 @@ contract UniversalDelegatorTest is Test { assertEq(delegator.getAllocated(slot2), 40); assertEq(delegator.getAllocated(slot3), 0); - assertEq(delegator.getUnallocated(0), 0); + assertEq(_unallocated3(0, slot1, slot2, slot3), 0); } function test_increaseLimit_allowsLastChild_withoutUnallocated() public { _deposit(alice, 100); - delegator.createSlot(0, false, 30); - delegator.createSlot(0, false, 30); + _createSlot(0, false, 30); + _createSlot(0, false, 30); uint96 slot1 = uint96(0).createIndex(uint32(1)); uint96 slot2 = uint96(0).createIndex(uint32(2)); @@ -262,14 +300,14 @@ contract UniversalDelegatorTest is Test { assertEq(delegator.getAllocated(slot1), 30); assertEq(delegator.getAllocated(slot2), 70); - assertEq(delegator.getUnallocated(0), 0); + assertEq(_unallocated2(0, slot1, slot2), 0); } function test_decreaseLimit_schedulesPendingFree_untilDelayExpires() public { _deposit(alice, 100); - delegator.createSlot(0, false, 60); - delegator.createSlot(0, false, 30); + _createSlot(0, false, 60); + _createSlot(0, false, 30); uint96 slot1 = uint96(0).createIndex(uint32(1)); uint96 slot2 = uint96(0).createIndex(uint32(2)); @@ -281,25 +319,25 @@ contract UniversalDelegatorTest is Test { assertEq(delegator.getAvailable(0), 80); assertEq(delegator.getAllocated(slot1), 40); assertEq(delegator.getAllocated(slot2), 30); - assertEq(delegator.getUnallocated(0), 10); + assertEq(_unallocated2(0, slot1, slot2), 10); vm.warp(4); assertEq(delegator.getAvailable(0), 100); assertEq(delegator.getAllocated(slot1), 40); assertEq(delegator.getAllocated(slot2), 30); - assertEq(delegator.getUnallocated(0), 30); + assertEq(_unallocated2(0, slot1, slot2), 30); } function test_pendingFree_respectsAllocationWhenResizingChildren() public { _deposit(alice, 555); - delegator.createSlot(0, false, 555); + _createSlot(0, false, 555); uint96 group = uint96(0).createIndex(uint32(1)); - delegator.createSlot(group, false, 444); + _createSlot(group, false, 444); uint96 networkSlot = group.createIndex(uint32(1)); - delegator.createSlot(networkSlot, false, 444); + _createSlot(networkSlot, false, 444); uint96 operatorSlot = networkSlot.createIndex(uint32(1)); assertEq(delegator.getAllocated(group), 555); @@ -331,13 +369,13 @@ contract UniversalDelegatorTest is Test { function test_pendingFree_accumulatesOnRepeatedOperatorDecrease() public { _deposit(alice, 555); - delegator.createSlot(0, false, 555); + _createSlot(0, false, 555); uint96 group = uint96(0).createIndex(uint32(1)); - delegator.createSlot(group, false, 444); + _createSlot(group, false, 444); uint96 networkSlot = group.createIndex(uint32(1)); - delegator.createSlot(networkSlot, false, 444); + _createSlot(networkSlot, false, 444); uint96 operatorSlot = networkSlot.createIndex(uint32(1)); vm.warp(1); @@ -362,11 +400,11 @@ contract UniversalDelegatorTest is Test { function test_sharedGroup_allowsNetworkRestaking_betweenDepth2Siblings() public { _deposit(alice, 100); - delegator.createSlot(0, true, 100); + _createSlot(0, true, 100); uint96 group = uint96(0).createIndex(uint32(1)); - delegator.createSlot(group, false, 80); - delegator.createSlot(group, false, 80); + _createSlot(group, false, 80); + _createSlot(group, false, 80); uint96 net1 = group.createIndex(uint32(1)); uint96 net2 = group.createIndex(uint32(2)); @@ -378,14 +416,14 @@ contract UniversalDelegatorTest is Test { function test_depth3Operators_areIsolatedWithinNetwork() public { _deposit(alice, 100); - delegator.createSlot(0, true, 100); + _createSlot(0, true, 100); uint96 group = uint96(0).createIndex(uint32(1)); - delegator.createSlot(group, false, 80); + _createSlot(group, false, 80); uint96 net1 = group.createIndex(uint32(1)); - delegator.createSlot(net1, false, 50); - delegator.createSlot(net1, false, 50); + _createSlot(net1, false, 50); + _createSlot(net1, false, 50); uint96 op1 = net1.createIndex(uint32(1)); uint96 op2 = net1.createIndex(uint32(2)); @@ -395,9 +433,9 @@ contract UniversalDelegatorTest is Test { } function test_isolatedGroups_prioritizedOverTime() public { - delegator.createSlot(0, false, 30); - delegator.createSlot(0, false, 50); - delegator.createSlot(0, false, 100); + _createSlot(0, false, 30); + _createSlot(0, false, 50); + _createSlot(0, false, 100); uint96 slot1 = uint96(0).createIndex(uint32(1)); uint96 slot2 = uint96(0).createIndex(uint32(2)); @@ -421,11 +459,11 @@ contract UniversalDelegatorTest is Test { function test_isolatedNetworks_followGroupPriority() public { _deposit(alice, 150); - delegator.createSlot(0, false, 200); + _createSlot(0, false, 200); uint96 group = uint96(0).createIndex(uint32(1)); - delegator.createSlot(group, false, 60); - delegator.createSlot(group, false, 120); + _createSlot(group, false, 60); + _createSlot(group, false, 120); uint96 net1 = group.createIndex(uint32(1)); uint96 net2 = group.createIndex(uint32(2)); @@ -435,14 +473,14 @@ contract UniversalDelegatorTest is Test { } function test_isolatedOperators_prioritizedAfterStakeDecrease() public { - delegator.createSlot(0, false, 1000); + _createSlot(0, false, 1000); uint96 group = uint96(0).createIndex(uint32(1)); - delegator.createSlot(group, false, 1000); + _createSlot(group, false, 1000); uint96 networkSlot = group.createIndex(uint32(1)); - delegator.createSlot(networkSlot, false, 70); - delegator.createSlot(networkSlot, false, 70); + _createSlot(networkSlot, false, 70); + _createSlot(networkSlot, false, 70); uint96 op1 = networkSlot.createIndex(uint32(1)); uint96 op2 = networkSlot.createIndex(uint32(2)); @@ -462,8 +500,8 @@ contract UniversalDelegatorTest is Test { function test_isolatedSlots_pendingFree_delaysReallocation() public { _deposit(alice, 100); - delegator.createSlot(0, false, 70); - delegator.createSlot(0, false, 70); + _createSlot(0, false, 70); + _createSlot(0, false, 70); uint96 slot1 = uint96(0).createIndex(uint32(1)); uint96 slot2 = uint96(0).createIndex(uint32(2)); @@ -486,8 +524,8 @@ contract UniversalDelegatorTest is Test { function test_isolatedSlots_lateSizeIncrease_doesNotAffectEarlier() public { _deposit(alice, 90); - delegator.createSlot(0, false, 50); - delegator.createSlot(0, false, 60); + _createSlot(0, false, 50); + _createSlot(0, false, 60); uint96 slot1 = uint96(0).createIndex(uint32(1)); uint96 slot2 = uint96(0).createIndex(uint32(2)); @@ -530,31 +568,31 @@ contract UniversalDelegatorTest is Test { bytes32 subnetwork2 = network2.subnetwork(0); bytes32 subnetwork3 = network3.subnetwork(0); - delegator.createSlot(0, true, 60); - delegator.createSlot(0, false, 40); + _createSlot(0, true, 60); + _createSlot(0, false, 40); uint96 group1 = uint96(0).createIndex(uint32(1)); uint96 group2 = uint96(0).createIndex(uint32(2)); - delegator.createSlot(group1, false, 60); - delegator.createSlot(group1, false, 60); + _createSlot(group1, false, 60); + _createSlot(group1, false, 60); uint96 netSlot1 = group1.createIndex(uint32(1)); uint96 netSlot2 = group1.createIndex(uint32(2)); delegator.assignNetwork(netSlot1, subnetwork1); delegator.assignNetwork(netSlot2, subnetwork2); - delegator.createSlot(netSlot1, false, 60); + _createSlot(netSlot1, false, 60); uint96 opSlot1 = netSlot1.createIndex(uint32(1)); delegator.assignOperator(opSlot1, operator1); - delegator.createSlot(netSlot2, false, 60); + _createSlot(netSlot2, false, 60); uint96 opSlot2 = netSlot2.createIndex(uint32(1)); delegator.assignOperator(opSlot2, operator2); - delegator.createSlot(group2, false, 40); + _createSlot(group2, false, 40); uint96 netSlot3 = group2.createIndex(uint32(1)); delegator.assignNetwork(netSlot3, subnetwork3); - delegator.createSlot(netSlot3, false, 40); + _createSlot(netSlot3, false, 40); uint96 opSlot3 = netSlot3.createIndex(uint32(1)); delegator.assignOperator(opSlot3, operator3); @@ -589,21 +627,21 @@ contract UniversalDelegatorTest is Test { bytes32 subnetwork1 = network1.subnetwork(0); bytes32 subnetwork2 = network2.subnetwork(0); - delegator.createSlot(0, true, 60); + _createSlot(0, true, 60); uint96 group = uint96(0).createIndex(uint32(1)); - delegator.createSlot(group, false, 60); - delegator.createSlot(group, false, 60); + _createSlot(group, false, 60); + _createSlot(group, false, 60); uint96 netSlot1 = group.createIndex(uint32(1)); uint96 netSlot2 = group.createIndex(uint32(2)); delegator.assignNetwork(netSlot1, subnetwork1); delegator.assignNetwork(netSlot2, subnetwork2); - delegator.createSlot(netSlot1, false, 60); + _createSlot(netSlot1, false, 60); uint96 opSlot1 = netSlot1.createIndex(uint32(1)); delegator.assignOperator(opSlot1, operator1); - delegator.createSlot(netSlot2, false, 60); + _createSlot(netSlot2, false, 60); uint96 opSlot2 = netSlot2.createIndex(uint32(1)); delegator.assignOperator(opSlot2, operator2); @@ -636,21 +674,21 @@ contract UniversalDelegatorTest is Test { bytes32 subnetwork1 = network1.subnetwork(0); bytes32 subnetwork2 = network2.subnetwork(0); - delegator.createSlot(0, true, 200); + _createSlot(0, true, 200); uint96 group = uint96(0).createIndex(uint32(1)); - delegator.createSlot(group, false, 200); - delegator.createSlot(group, false, 200); + _createSlot(group, false, 200); + _createSlot(group, false, 200); uint96 netSlot1 = group.createIndex(uint32(1)); uint96 netSlot2 = group.createIndex(uint32(2)); delegator.assignNetwork(netSlot1, subnetwork1); delegator.assignNetwork(netSlot2, subnetwork2); - delegator.createSlot(netSlot1, false, 200); + _createSlot(netSlot1, false, 200); uint96 opSlot1 = netSlot1.createIndex(uint32(1)); delegator.assignOperator(opSlot1, operator1); - delegator.createSlot(netSlot2, false, 200); + _createSlot(netSlot2, false, 200); uint96 opSlot2 = netSlot2.createIndex(uint32(1)); delegator.assignOperator(opSlot2, operator2); @@ -678,8 +716,8 @@ contract UniversalDelegatorTest is Test { uint256 cap1 = bound(size1, 0, MAX_AMOUNT); uint256 cap2 = bound(size2, 0, MAX_AMOUNT); - delegator.createSlot(0, false, cap1); - delegator.createSlot(0, false, cap2); + _createSlot(0, false, cap1); + _createSlot(0, false, cap2); uint96 slot1 = uint96(0).createIndex(uint32(1)); uint96 slot2 = uint96(0).createIndex(uint32(2)); @@ -699,14 +737,14 @@ contract UniversalDelegatorTest is Test { uint256 cap1 = bound(size1, 0, MAX_AMOUNT); uint256 cap2 = bound(size2, 0, MAX_AMOUNT); - delegator.createSlot(0, false, MAX_AMOUNT); + _createSlot(0, false, MAX_AMOUNT); uint96 group = uint96(0).createIndex(uint32(1)); - delegator.createSlot(group, false, MAX_AMOUNT); + _createSlot(group, false, MAX_AMOUNT); uint96 networkSlot = group.createIndex(uint32(1)); - delegator.createSlot(networkSlot, false, cap1); - delegator.createSlot(networkSlot, false, cap2); + _createSlot(networkSlot, false, cap1); + _createSlot(networkSlot, false, cap2); uint96 op1 = networkSlot.createIndex(uint32(1)); uint96 op2 = networkSlot.createIndex(uint32(2)); @@ -730,8 +768,8 @@ contract UniversalDelegatorTest is Test { uint256 cap1 = bound(size1, 0, MAX_AMOUNT); uint256 cap2 = bound(size2, 0, MAX_AMOUNT); - delegator.createSlot(0, false, cap1); - delegator.createSlot(0, false, cap2); + _createSlot(0, false, cap1); + _createSlot(0, false, cap2); uint96 slot1 = uint96(0).createIndex(uint32(1)); uint96 slot2 = uint96(0).createIndex(uint32(2)); @@ -753,101 +791,340 @@ contract UniversalDelegatorTest is Test { assertEq(delegator.getAllocated(slot2), expected2); } - function test_isRestaked_trueWhenGroupIsShared() public { + function testFuzz_isolatedShares_doNotOverlapAtRoot( + uint256 depositAmount, + uint256 size1, + uint256 size2, + uint256 share1Seed, + uint256 share2Seed + ) public { + uint256 maxSize = (MAX_AMOUNT - 1) / 2; + uint256 cap1 = bound(size1, 0, maxSize); + uint256 cap2 = bound(size2, 0, maxSize); + uint256 totalSize = cap1 + cap2; + uint256 amount = bound(depositAmount, totalSize + 1, MAX_AMOUNT); + uint256 share1 = bound(share1Seed, 1, delegator.MAX_SHARES() - 1); + uint256 share2 = bound(share2Seed, 1, delegator.MAX_SHARES() - share1); + + _createSlot(0, false, cap1); + _createSlot(0, false, cap2); + uint96 slot1 = uint96(0).createIndex(uint32(1)); + uint96 slot2 = uint96(0).createIndex(uint32(2)); + + delegator.setShare(slot1, uint208(share1)); + delegator.setShare(slot2, uint208(share2)); + + _deposit(alice, amount); + + uint256 available = delegator.getAvailable(0); + uint256 allocated1 = delegator.getAllocated(slot1); + uint256 allocated2 = delegator.getAllocated(slot2); + uint256 unallocated = available - totalSize; + uint256 upper = totalSize + (unallocated * (share1 + share2)) / delegator.MAX_SHARES(); + + assertGe(allocated1, cap1); + assertGe(allocated2, cap2); + assertLe(allocated1 + allocated2, available); + assertLe(allocated1 + allocated2, upper); + } + + function testFuzz_isolatedShares_doNotOverlapInGroup( + uint256 depositAmount, + uint256 size1, + uint256 size2, + uint256 share1Seed, + uint256 share2Seed + ) public { + uint256 maxSize = (MAX_AMOUNT - 1) / 2; + uint256 cap1 = bound(size1, 0, maxSize); + uint256 cap2 = bound(size2, 0, maxSize); + uint256 totalSize = cap1 + cap2; + uint256 amount = bound(depositAmount, totalSize + 1, MAX_AMOUNT); + uint256 share1 = bound(share1Seed, 1, delegator.MAX_SHARES() - 1); + uint256 share2 = bound(share2Seed, 1, delegator.MAX_SHARES() - share1); + + _createSlot(0, false, MAX_AMOUNT); + uint96 group = uint96(0).createIndex(uint32(1)); + + _createSlot(group, false, cap1); + _createSlot(group, false, cap2); + uint96 slot1 = group.createIndex(uint32(1)); + uint96 slot2 = group.createIndex(uint32(2)); + + delegator.setShare(slot1, uint208(share1)); + delegator.setShare(slot2, uint208(share2)); + + _deposit(alice, amount); + + uint256 available = delegator.getAvailable(group); + uint256 allocated1 = delegator.getAllocated(slot1); + uint256 allocated2 = delegator.getAllocated(slot2); + uint256 unallocated = available - totalSize; + uint256 upper = totalSize + (unallocated * (share1 + share2)) / delegator.MAX_SHARES(); + + assertGe(allocated1, cap1); + assertGe(allocated2, cap2); + assertLe(allocated1 + allocated2, available); + assertLe(allocated1 + allocated2, upper); + } + + function testFuzz_isolatedShares_captureInvariantAcrossNetworks( + uint256 depositAmount, + uint256 size1, + uint256 size2, + uint256 share1Seed, + uint256 share2Seed + ) public { + address network1 = makeAddr("network1"); + address network2 = makeAddr("network2"); + address middleware = makeAddr("middleware"); + address operator1 = alice; + address operator2 = bob; + + _registerNetwork(network1, middleware); + _registerNetwork(network2, middleware); + _registerOperator(operator1); + _registerOperator(operator2); + _optIn(operator1, network1); + _optIn(operator2, network2); + + uint256 minUnallocated = 1000; + uint256 maxSize = (MAX_AMOUNT - minUnallocated) / 2; + uint256 cap1 = bound(size1, 1, maxSize); + uint256 cap2 = bound(size2, 0, maxSize); + uint256 totalSize = cap1 + cap2; + uint256 amount = bound(depositAmount, totalSize + minUnallocated, MAX_AMOUNT); + uint256 minShare = delegator.MAX_SHARES() / minUnallocated; + uint256 share1 = bound(share1Seed, minShare, delegator.MAX_SHARES()); + uint256 share2 = bound(share2Seed, 0, delegator.MAX_SHARES() - share1); + + _createSlot(0, false, MAX_AMOUNT); + uint96 group = uint96(0).createIndex(uint32(1)); + + _createSlot(group, false, cap1); + _createSlot(group, false, cap2); + uint96 netSlot1 = group.createIndex(uint32(1)); + uint96 netSlot2 = group.createIndex(uint32(2)); + + bytes32 subnetwork1 = network1.subnetwork(0); + bytes32 subnetwork2 = network2.subnetwork(0); + delegator.assignNetwork(netSlot1, subnetwork1); + delegator.assignNetwork(netSlot2, subnetwork2); + + _createSlot(netSlot1, false, cap1); + uint96 opSlot1 = netSlot1.createIndex(uint32(1)); + delegator.assignOperator(opSlot1, operator1); + + _createSlot(netSlot2, false, cap2); + uint96 opSlot2 = netSlot2.createIndex(uint32(1)); + delegator.assignOperator(opSlot2, operator2); + + vm.warp(1); + delegator.setShare(netSlot1, uint208(share1)); + if (share2 != 0) { + delegator.setShare(netSlot2, uint208(share2)); + } + delegator.setShare(opSlot1, uint208(delegator.MAX_SHARES())); + delegator.setShare(opSlot2, uint208(delegator.MAX_SHARES())); + + vm.warp(EPOCH_DURATION + 1); + _deposit(alice, amount); + uint48 captureTimestamp = uint48(block.timestamp); + + vm.warp(captureTimestamp + 1); + uint256 slashableBefore = slasher.slashableStake(subnetwork1, operator1, captureTimestamp, ""); + vm.assume(slashableBefore > 0); + + uint256 shifted = share1 + share2; + delegator.setShare(netSlot1, 0); + if (shifted != share2) { + delegator.setShare(netSlot2, uint208(shifted)); + } + + vm.warp(captureTimestamp + 1); + + uint256 slashableAfter = slasher.slashableStake(subnetwork1, operator1, captureTimestamp, ""); + assertEq(slashableAfter, slashableBefore); + + vm.startPrank(middleware); + assertEq(slasher.slash(subnetwork1, operator1, slashableBefore, captureTimestamp, ""), slashableBefore); + vm.stopPrank(); + } + + function testFuzz_isolatedShares_captureInvariantAcrossOperators( + uint256 depositAmount, + uint256 size1, + uint256 size2, + uint256 share1Seed, + uint256 share2Seed + ) public { + address network = makeAddr("network"); + address middleware = makeAddr("middleware"); + address operator1 = alice; + address operator2 = bob; + + _registerNetwork(network, middleware); + _registerOperator(operator1); + _registerOperator(operator2); + _optIn(operator1, network); + _optIn(operator2, network); + + uint256 minUnallocated = 1000; + uint256 maxSize = (MAX_AMOUNT - minUnallocated) / 2; + uint256 cap1 = bound(size1, 1, maxSize); + uint256 cap2 = bound(size2, 0, maxSize); + uint256 totalSize = cap1 + cap2; + uint256 networkSize = totalSize + minUnallocated; + uint256 amount = bound(depositAmount, networkSize, MAX_AMOUNT); + uint256 minShare = delegator.MAX_SHARES() / minUnallocated; + uint256 share1 = bound(share1Seed, minShare, delegator.MAX_SHARES()); + uint256 share2 = bound(share2Seed, 0, delegator.MAX_SHARES() - share1); + + _createSlot(0, false, MAX_AMOUNT); + uint96 group = uint96(0).createIndex(uint32(1)); + + _createSlot(group, false, networkSize); + uint96 networkSlot = group.createIndex(uint32(1)); + bytes32 subnetwork = network.subnetwork(0); + delegator.assignNetwork(networkSlot, subnetwork); + + _createSlot(networkSlot, false, cap1); + _createSlot(networkSlot, false, cap2); + uint96 opSlot1 = networkSlot.createIndex(uint32(1)); + uint96 opSlot2 = networkSlot.createIndex(uint32(2)); + delegator.assignOperator(opSlot1, operator1); + delegator.assignOperator(opSlot2, operator2); + + vm.warp(1); + delegator.setShare(opSlot1, uint208(share1)); + if (share2 != 0) { + delegator.setShare(opSlot2, uint208(share2)); + } + + vm.warp(EPOCH_DURATION + 1); + _deposit(alice, amount); + uint48 captureTimestamp = uint48(block.timestamp); + + vm.warp(captureTimestamp + 1); + uint256 slashableBefore = slasher.slashableStake(subnetwork, operator1, captureTimestamp, ""); + vm.assume(slashableBefore > 0); + + uint256 shifted = share1 + share2; + delegator.setShare(opSlot1, 0); + if (shifted != share2) { + delegator.setShare(opSlot2, uint208(shifted)); + } + + uint256 slashableAfter = slasher.slashableStake(subnetwork, operator1, captureTimestamp, ""); + assertEq(slashableAfter, slashableBefore); + + vm.startPrank(middleware); + assertEq(slasher.slash(subnetwork, operator1, slashableBefore, captureTimestamp, ""), slashableBefore); + vm.stopPrank(); + } + + function test_isShared_trueWhenGroupIsShared() public { bytes32 subnetwork = bytes32(uint256(1)); _deposit(alice, 100); - delegator.createSlot(0, true, 100); + _createSlot(0, true, 100); uint96 group = uint96(0).createIndex(uint32(1)); - delegator.createSlot(group, false, 100); + _createSlot(group, false, 100); uint96 networkSlot = group.createIndex(uint32(1)); delegator.assignNetwork(networkSlot, subnetwork); - delegator.createSlot(networkSlot, false, 100); + _createSlot(networkSlot, false, 100); uint96 operatorSlot = networkSlot.createIndex(uint32(1)); delegator.assignOperator(operatorSlot, alice); - assertTrue(delegator.isRestaked(subnetwork, alice)); - assertTrue(delegator.isRestakedAt(subnetwork, alice, uint48(block.timestamp), "")); + assertTrue(delegator.isShared(subnetwork, alice)); + assertTrue(delegator.isSharedAt(subnetwork, alice, uint48(block.timestamp), "")); } - function test_isRestaked_falseWhenGroupNotShared() public { + function test_isShared_falseWhenGroupNotShared() public { bytes32 subnetwork = bytes32(uint256(1)); _deposit(alice, 100); - delegator.createSlot(0, false, 100); + _createSlot(0, false, 100); uint96 group = uint96(0).createIndex(uint32(1)); - delegator.createSlot(group, false, 100); + _createSlot(group, false, 100); uint96 networkSlot = group.createIndex(uint32(1)); delegator.assignNetwork(networkSlot, subnetwork); - delegator.createSlot(networkSlot, false, 100); + _createSlot(networkSlot, false, 100); uint96 operatorSlot = networkSlot.createIndex(uint32(1)); delegator.assignOperator(operatorSlot, alice); - assertFalse(delegator.isRestaked(subnetwork, alice)); - assertFalse(delegator.isRestakedAt(subnetwork, alice, uint48(block.timestamp), "")); + assertFalse(delegator.isShared(subnetwork, alice)); + assertFalse(delegator.isSharedAt(subnetwork, alice, uint48(block.timestamp), "")); } - function test_onlyCuratorRole_enforced() public { + function test_onlyRoles_enforced() public { vm.startPrank(bob); vm.expectRevert( abi.encodeWithSelector( - IAccessControl.AccessControlUnauthorizedAccount.selector, bob, delegator.CURATOR_ROLE() + IAccessControl.AccessControlUnauthorizedAccount.selector, bob, delegator.CREATE_SLOT_ROLE() ) ); - delegator.createSlot(0, false, 1); + _createSlot(0, false, 1); vm.expectRevert( abi.encodeWithSelector( - IAccessControl.AccessControlUnauthorizedAccount.selector, bob, delegator.CURATOR_ROLE() + IAccessControl.AccessControlUnauthorizedAccount.selector, bob, delegator.SET_IS_SHARED_ROLE() ) ); delegator.setIsShared(uint96(0).createIndex(uint32(1)), true); vm.expectRevert( abi.encodeWithSelector( - IAccessControl.AccessControlUnauthorizedAccount.selector, bob, delegator.CURATOR_ROLE() + IAccessControl.AccessControlUnauthorizedAccount.selector, bob, delegator.SET_SIZE_ROLE() ) ); delegator.setSize(uint96(0).createIndex(uint32(1)), 1); vm.expectRevert( abi.encodeWithSelector( - IAccessControl.AccessControlUnauthorizedAccount.selector, bob, delegator.CURATOR_ROLE() + IAccessControl.AccessControlUnauthorizedAccount.selector, bob, delegator.SET_SHARE_ROLE() + ) + ); + delegator.setShare(uint96(0).createIndex(uint32(1)), 1); + + vm.expectRevert( + abi.encodeWithSelector( + IAccessControl.AccessControlUnauthorizedAccount.selector, bob, delegator.SWAP_SLOTS_ROLE() ) ); delegator.swapSlots(uint96(0).createIndex(uint32(1)), uint96(0).createIndex(uint32(2))); vm.expectRevert( abi.encodeWithSelector( - IAccessControl.AccessControlUnauthorizedAccount.selector, bob, delegator.CURATOR_ROLE() + IAccessControl.AccessControlUnauthorizedAccount.selector, bob, delegator.ASSIGN_NETWORK_ROLE() ) ); delegator.assignNetwork(uint96(0).createIndex(uint32(1)), bytes32(uint256(1))); vm.expectRevert( abi.encodeWithSelector( - IAccessControl.AccessControlUnauthorizedAccount.selector, bob, delegator.CURATOR_ROLE() + IAccessControl.AccessControlUnauthorizedAccount.selector, bob, delegator.UNASSIGN_NETWORK_ROLE() ) ); delegator.unassignNetwork(bytes32(uint256(1))); vm.expectRevert( abi.encodeWithSelector( - IAccessControl.AccessControlUnauthorizedAccount.selector, bob, delegator.CURATOR_ROLE() + IAccessControl.AccessControlUnauthorizedAccount.selector, bob, delegator.ASSIGN_OPERATOR_ROLE() ) ); delegator.assignOperator(uint96(0).createIndex(uint32(1)), bob); vm.expectRevert( abi.encodeWithSelector( - IAccessControl.AccessControlUnauthorizedAccount.selector, bob, delegator.CURATOR_ROLE() + IAccessControl.AccessControlUnauthorizedAccount.selector, bob, delegator.UNASSIGN_OPERATOR_ROLE() ) ); delegator.unassignOperator(uint96(0).createIndex(uint32(1)), bob); @@ -856,13 +1133,13 @@ contract UniversalDelegatorTest is Test { } function test_depthGuards_enforced() public { - delegator.createSlot(0, false, 100); + _createSlot(0, false, 100); uint96 group = uint96(0).createIndex(uint32(1)); - delegator.createSlot(group, false, 100); + _createSlot(group, false, 100); uint96 networkSlot = group.createIndex(uint32(1)); - delegator.createSlot(networkSlot, false, 100); + _createSlot(networkSlot, false, 100); uint96 operatorSlot = networkSlot.createIndex(uint32(1)); vm.expectRevert(IUniversalDelegator.WrongDepth.selector); @@ -881,7 +1158,7 @@ contract UniversalDelegatorTest is Test { delegator.assignOperator(networkSlot, alice); vm.expectRevert(IUniversalDelegator.WrongDepth.selector); - delegator.createSlot(group, true, 1); + _createSlot(group, true, 1); } function test_networkAssignment_duplicateAndUnassignChecks() public { @@ -892,11 +1169,11 @@ contract UniversalDelegatorTest is Test { _deposit(alice, 100); - delegator.createSlot(0, false, 100); + _createSlot(0, false, 100); uint96 group = uint96(0).createIndex(uint32(1)); - delegator.createSlot(group, false, 100); - delegator.createSlot(group, false, 100); + _createSlot(group, false, 100); + _createSlot(group, false, 100); uint96 net1 = group.createIndex(uint32(1)); uint96 net2 = group.createIndex(uint32(2)); @@ -910,20 +1187,40 @@ contract UniversalDelegatorTest is Test { _withdraw(alice, 100); delegator.unassignNetwork(subnetwork); - assertEq(delegator.slotOfNetwork(subnetwork), 0); + assertEq(delegator.getSlotOfNetwork(subnetwork), 0); + } + + function test_networkAssignment_revertsWhenSlotAlreadyAssigned() public { + bytes32 subnetwork1 = bytes32(uint256(1)); + bytes32 subnetwork2 = bytes32(uint256(2)); + + _createSlot(0, false, 100); + uint96 group = uint96(0).createIndex(uint32(1)); + + _createSlot(group, false, 100); + uint96 networkSlot = group.createIndex(uint32(1)); + + delegator.assignNetwork(networkSlot, subnetwork1); + + vm.expectRevert(IUniversalDelegator.NetworkAlreadyAssigned.selector); + delegator.assignNetwork(networkSlot, subnetwork2); + + delegator.unassignNetwork(subnetwork1); + delegator.assignNetwork(networkSlot, subnetwork2); + assertEq(delegator.getSlotOfNetwork(subnetwork2), networkSlot); } function test_operatorAssignment_duplicateAndUnassignChecks() public { _deposit(alice, 100); - delegator.createSlot(0, false, 100); + _createSlot(0, false, 100); uint96 group = uint96(0).createIndex(uint32(1)); - delegator.createSlot(group, false, 100); + _createSlot(group, false, 100); uint96 networkSlot = group.createIndex(uint32(1)); - delegator.createSlot(networkSlot, false, 60); - delegator.createSlot(networkSlot, false, 60); + _createSlot(networkSlot, false, 60); + _createSlot(networkSlot, false, 60); uint96 operatorSlot1 = networkSlot.createIndex(uint32(1)); uint96 operatorSlot2 = networkSlot.createIndex(uint32(2)); @@ -940,13 +1237,33 @@ contract UniversalDelegatorTest is Test { _withdraw(alice, 100); delegator.unassignOperator(networkSlot, alice); - assertEq(delegator.slotOfOperator(networkSlot, alice), 0); + assertEq(delegator.getSlotOfOperator(networkSlot, alice), 0); + } + + function test_operatorAssignment_revertsWhenSlotAlreadyAssigned() public { + _createSlot(0, false, 100); + uint96 group = uint96(0).createIndex(uint32(1)); + + _createSlot(group, false, 100); + uint96 networkSlot = group.createIndex(uint32(1)); + + _createSlot(networkSlot, false, 100); + uint96 operatorSlot = networkSlot.createIndex(uint32(1)); + + delegator.assignOperator(operatorSlot, alice); + + vm.expectRevert(IUniversalDelegator.OperatorAlreadyAssigned.selector); + delegator.assignOperator(operatorSlot, bob); + + delegator.unassignOperator(networkSlot, alice); + delegator.assignOperator(operatorSlot, bob); + assertEq(delegator.getSlotOfOperator(networkSlot, bob), operatorSlot); } function test_setIsShared_revertsWhenAllocated() public { _deposit(alice, 1); - delegator.createSlot(0, false, 1); + _createSlot(0, false, 1); uint96 group = uint96(0).createIndex(uint32(1)); vm.expectRevert(IUniversalDelegator.SlotAllocated.selector); @@ -954,11 +1271,11 @@ contract UniversalDelegatorTest is Test { } function test_setIsShared_togglesNetworkRestaking() public { - delegator.createSlot(0, false, 100); + _createSlot(0, false, 100); uint96 group = uint96(0).createIndex(uint32(1)); - delegator.createSlot(group, false, 80); - delegator.createSlot(group, false, 80); + _createSlot(group, false, 80); + _createSlot(group, false, 80); uint96 net1 = group.createIndex(uint32(1)); uint96 net2 = group.createIndex(uint32(2)); @@ -978,8 +1295,8 @@ contract UniversalDelegatorTest is Test { function test_swapSlots_changesAllocationAfterStakeDecrease() public { _deposit(alice, 100); - delegator.createSlot(0, false, 30); - delegator.createSlot(0, false, 50); + _createSlot(0, false, 30); + _createSlot(0, false, 50); uint96 slot1 = uint96(0).createIndex(uint32(1)); uint96 slot2 = uint96(0).createIndex(uint32(2)); @@ -997,8 +1314,8 @@ contract UniversalDelegatorTest is Test { function test_swapSlots_revertsWrongOrder() public { _deposit(alice, 100); - delegator.createSlot(0, false, 10); - delegator.createSlot(0, false, 10); + _createSlot(0, false, 10); + _createSlot(0, false, 10); uint96 slot1 = uint96(0).createIndex(uint32(1)); uint96 slot2 = uint96(0).createIndex(uint32(2)); @@ -1009,12 +1326,12 @@ contract UniversalDelegatorTest is Test { function test_swapSlots_revertsNotSameParent() public { _deposit(alice, 100); - delegator.createSlot(0, false, 10); + _createSlot(0, false, 10); uint96 rootSlot = uint96(0).createIndex(uint32(1)); - delegator.createSlot(0, false, 10); + _createSlot(0, false, 10); uint96 group = uint96(0).createIndex(uint32(2)); - delegator.createSlot(group, false, 10); + _createSlot(group, false, 10); uint96 networkSlot = group.createIndex(uint32(1)); vm.expectRevert(IUniversalDelegator.NotSameParent.selector); @@ -1024,8 +1341,8 @@ contract UniversalDelegatorTest is Test { function test_swapSlots_revertsNotSameAllocated() public { _deposit(alice, 3); - delegator.createSlot(0, false, 5); - delegator.createSlot(0, false, 5); + _createSlot(0, false, 5); + _createSlot(0, false, 5); uint96 slot1 = uint96(0).createIndex(uint32(1)); uint96 slot2 = uint96(0).createIndex(uint32(2)); @@ -1036,8 +1353,8 @@ contract UniversalDelegatorTest is Test { function test_swapSlots_revertsPartiallyAllocated() public { _deposit(alice, 70); - delegator.createSlot(0, false, 50); - delegator.createSlot(0, false, 50); + _createSlot(0, false, 50); + _createSlot(0, false, 50); uint96 slot1 = uint96(0).createIndex(uint32(1)); uint96 slot2 = uint96(0).createIndex(uint32(2)); @@ -1048,7 +1365,7 @@ contract UniversalDelegatorTest is Test { function test_getAvailableAt_doesNotUnderflowForSmallTimestamps() public { _deposit(alice, 100); - delegator.createSlot(0, false, 60); + _createSlot(0, false, 60); uint96 slot1 = uint96(0).createIndex(uint32(1)); vm.warp(1); @@ -1058,6 +1375,27 @@ contract UniversalDelegatorTest is Test { assertEq(delegator.getAvailableAt(0, 4, ""), 100); } + function _createSlot(uint96 parentIndex, bool isShared, uint256 size) internal { + delegator.createSlot(parentIndex, isShared, size, 0); + } + + function _unallocated2(uint96 parentIndex, uint96 slot1, uint96 slot2) internal view returns (uint256) { + uint256 available = delegator.getAvailable(parentIndex); + uint256 allocated = delegator.getAllocated(slot1) + delegator.getAllocated(slot2); + return available > allocated ? available - allocated : 0; + } + + function _unallocated3(uint96 parentIndex, uint96 slot1, uint96 slot2, uint96 slot3) + internal + view + returns (uint256) + { + uint256 available = delegator.getAvailable(parentIndex); + uint256 allocated = + delegator.getAllocated(slot1) + delegator.getAllocated(slot2) + delegator.getAllocated(slot3); + return available > allocated ? available - allocated : 0; + } + function _registerOperator(address operator) internal { vm.startPrank(operator); operatorRegistry.registerOperator(); diff --git a/ui/src/pages/UniversalDelegatorConfigurator.tsx b/ui/src/pages/UniversalDelegatorConfigurator.tsx index ebf2e150..882df89a 100644 --- a/ui/src/pages/UniversalDelegatorConfigurator.tsx +++ b/ui/src/pages/UniversalDelegatorConfigurator.tsx @@ -81,12 +81,11 @@ function computeSlotMetrics(params: { pendingByIndex: Map; }): SlotMetrics { const key = params.index !== undefined ? params.index.toString() : null; - const allocatedRaw = key ? (params.allocationsByIndex.get(key) ?? 0n) : 0n; - const pendingRaw = key ? (params.pendingByIndex.get(key) ?? 0n) : 0n; + const allocatedRaw = key ? params.allocationsByIndex.get(key) ?? 0n : 0n; + const pendingRaw = key ? params.pendingByIndex.get(key) ?? 0n : 0n; const pendingValue = pendingRaw > allocatedRaw ? allocatedRaw : pendingRaw; const allocatedValue = saturatingSub(allocatedRaw, pendingValue); - const allocatedPct = - params.size > 0n ? Math.min(100, Number((allocatedValue * 10000n) / params.size) / 100) : 0; + const allocatedPct = params.size > 0n ? Math.min(100, Number((allocatedValue * 10000n) / params.size) / 100) : 0; const pendingPctRaw = params.size > 0n ? Number((pendingValue * 10000n) / params.size) / 100 : 0; const pendingPct = Math.max(0, Math.min(100 - allocatedPct, pendingPctRaw)); @@ -464,7 +463,7 @@ export function UniversalDelegatorConfigurator() { const index = availableIndices[i]; if (index === undefined) continue; const available = item.result as bigint; - const balance = index === 0n ? (rootBalance ?? 0n) : (onchainAllocationsByIndex.get(index.toString()) ?? 0n); + const balance = index === 0n ? rootBalance ?? 0n : onchainAllocationsByIndex.get(index.toString()) ?? 0n; map.set(index.toString(), saturatingSub(balance, available)); } } @@ -560,14 +559,7 @@ export function UniversalDelegatorConfigurator() { return { tone: "info" as const, message: "Loading on-chain data..." }; } return null; - }, [ - allocatedLoading, - availableLoading, - balancesLoading, - hasReadErrors, - isReconstructing, - onchainReadActive, - ]); + }, [allocatedLoading, availableLoading, balancesLoading, hasReadErrors, isReconstructing, onchainReadActive]); const encodedCalls = useMemo(() => encodeOpsToCalls(selectedOps), [selectedOps]); @@ -946,10 +938,10 @@ export function UniversalDelegatorConfigurator() { needsNetworks && needsOperators ? Boolean(groupNetworksCount && groupOperatorsCount) : needsNetworks - ? Boolean(groupNetworksCount) - : needsOperators - ? Boolean(groupOperatorsCount) - : true; + ? Boolean(groupNetworksCount) + : needsOperators + ? Boolean(groupOperatorsCount) + : true; const swapScope = useMemo((): { label: string; items: Array } => { if (zoom.kind === "all") return { label: "Groups", items: model.groups }; @@ -1091,7 +1083,7 @@ export function UniversalDelegatorConfigurator() { - + @@ -1225,15 +1217,15 @@ export function UniversalDelegatorConfigurator() {
- Allocated: {canReadBalances ? (rootBalance?.toString() ?? (balancesLoading ? "loading…" : "—")) : "—"} + Allocated: {canReadBalances ? rootBalance?.toString() ?? (balancesLoading ? "loading…" : "—") : "—"}
Pending:{" "} {!canReadBalances || !hasRootBalance ? "—" : pendingLoading - ? "loading…" - : (pendingByIndex.get("0") ?? 0n).toString()} + ? "loading…" + : (pendingByIndex.get("0") ?? 0n).toString()}
@@ -1489,7 +1481,9 @@ function NetworksRow(props: { hasRootBalance={props.hasRootBalance} onCopyIndex={props.onCopyIndex} onAddOperator={() => props.onAddOperator(network.id)} - onUpdateOperatorDraft={(operatorId, patch) => props.onUpdateOperatorDraft(network.id, operatorId, patch)} + onUpdateOperatorDraft={(operatorId, patch) => + props.onUpdateOperatorDraft(network.id, operatorId, patch) + } /> );